mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 07:50:25 +08:00
refactor: 使用泛型重构参数绑定等
This commit is contained in:
@@ -47,7 +47,7 @@ func (a *AccountLogin) ReqConfs() *req.Confs {
|
||||
|
||||
// @router /auth/accounts/login [post]
|
||||
func (a *AccountLogin) Login(rc *req.Ctx) {
|
||||
loginForm := req.BindJsonAndValid(rc, new(form.LoginForm))
|
||||
loginForm := req.BindJsonAndValid[*form.LoginForm](rc)
|
||||
ctx := rc.MetaCtx
|
||||
|
||||
accountLoginSecurity := config.GetAccountLoginSecurity()
|
||||
@@ -96,8 +96,7 @@ type OtpVerifyInfo struct {
|
||||
|
||||
// OTP双因素校验
|
||||
func (a *AccountLogin) OtpVerify(rc *req.Ctx) {
|
||||
otpVerify := new(form.OtpVerfiy)
|
||||
req.BindJsonAndValid(rc, otpVerify)
|
||||
otpVerify := req.BindJsonAndValid[*form.OtpVerfiy](rc)
|
||||
ctx := rc.MetaCtx
|
||||
|
||||
tokenKey := fmt.Sprintf("otp:token:%s", otpVerify.OtpToken)
|
||||
|
||||
@@ -47,7 +47,7 @@ func (a *LdapLogin) GetLdapEnabled(rc *req.Ctx) {
|
||||
|
||||
// @router /auth/ldap/login [post]
|
||||
func (a *LdapLogin) Login(rc *req.Ctx) {
|
||||
loginForm := req.BindJsonAndValid(rc, new(form.LoginForm))
|
||||
loginForm := req.BindJsonAndValid[*form.LoginForm](rc)
|
||||
ctx := rc.MetaCtx
|
||||
accountLoginSecurity := config.GetAccountLoginSecurity()
|
||||
// 判断是否有开启登录验证码校验
|
||||
|
||||
@@ -77,7 +77,7 @@ func (d *Db) ReqConfs() *req.Confs {
|
||||
|
||||
// @router /api/dbs [get]
|
||||
func (d *Db) Dbs(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery[*entity.DbQuery](rc, new(entity.DbQuery))
|
||||
queryCond := req.BindQuery[*entity.DbQuery](rc)
|
||||
|
||||
// 不存在可访问标签id,即没有可操作数据
|
||||
tags := d.tagApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
|
||||
@@ -115,9 +115,7 @@ func (d *Db) Dbs(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *Db) Save(rc *req.Ctx) {
|
||||
form := &form.DbForm{}
|
||||
db := req.BindJsonAndCopyTo[*entity.Db](rc, form, new(entity.Db))
|
||||
|
||||
form, db := req.BindJsonAndCopyTo[*form.DbForm, *entity.Db](rc)
|
||||
rc.ReqParam = form
|
||||
|
||||
biz.ErrIsNil(d.dbApp.SaveDb(rc.MetaCtx, db))
|
||||
@@ -137,7 +135,7 @@ func (d *Db) DeleteDb(rc *req.Ctx) {
|
||||
/** 数据库操作相关、执行sql等 ***/
|
||||
|
||||
func (d *Db) ExecSql(rc *req.Ctx) {
|
||||
form := req.BindJsonAndValid(rc, new(form.DbSqlExecForm))
|
||||
form := req.BindJsonAndValid[*form.DbSqlExecForm](rc)
|
||||
|
||||
ctx, cancel := context.WithTimeout(rc.MetaCtx, time.Duration(config.GetDbms().SqlExecTl)*time.Second)
|
||||
defer cancel()
|
||||
@@ -351,8 +349,7 @@ func (d *Db) GetSchemas(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *Db) CopyTable(rc *req.Ctx) {
|
||||
form := &form.DbCopyTableForm{}
|
||||
copy := req.BindJsonAndCopyTo[*dbi.DbCopyTable](rc, form, new(dbi.DbCopyTable))
|
||||
form, copy := req.BindJsonAndCopyTo[*form.DbCopyTableForm, *dbi.DbCopyTable](rc)
|
||||
|
||||
conn, err := d.dbApp.GetDbConn(rc.MetaCtx, form.Id, form.Db)
|
||||
biz.ErrIsNilAppendErr(err, "copy table error: %s")
|
||||
|
||||
@@ -50,22 +50,21 @@ func (d *DataSyncTask) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (d *DataSyncTask) Tasks(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery[*entity.DataSyncTaskQuery](rc, new(entity.DataSyncTaskQuery))
|
||||
queryCond := req.BindQuery[*entity.DataSyncTaskQuery](rc)
|
||||
res, err := d.dataSyncTaskApp.GetPageList(queryCond)
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = model.PageResultConv[*entity.DataSyncTask, *vo.DataSyncTaskListVO](res)
|
||||
}
|
||||
|
||||
func (d *DataSyncTask) Logs(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.DataSyncLogQuery))
|
||||
queryCond := req.BindQuery[*entity.DataSyncLogQuery](rc)
|
||||
res, err := d.dataSyncTaskApp.GetTaskLogList(queryCond)
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = model.PageResultConv[*entity.DataSyncLog, *vo.DataSyncLogListVO](res)
|
||||
}
|
||||
|
||||
func (d *DataSyncTask) SaveTask(rc *req.Ctx) {
|
||||
form := &form.DataSyncTaskForm{}
|
||||
task := req.BindJsonAndCopyTo[*entity.DataSyncTask](rc, form, new(entity.DataSyncTask))
|
||||
form, task := req.BindJsonAndCopyTo[*form.DataSyncTaskForm, *entity.DataSyncTask](rc)
|
||||
|
||||
// 解码base64 sql
|
||||
sqlStr, err := utils.AesDecryptByLa(task.DataSql, rc.GetLoginAccount())
|
||||
@@ -89,8 +88,7 @@ func (d *DataSyncTask) DeleteTask(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *DataSyncTask) ChangeStatus(rc *req.Ctx) {
|
||||
form := &form.DataSyncTaskStatusForm{}
|
||||
task := req.BindJsonAndCopyTo[*entity.DataSyncTask](rc, form, new(entity.DataSyncTask))
|
||||
form, task := req.BindJsonAndCopyTo[*form.DataSyncTaskStatusForm, *entity.DataSyncTask](rc)
|
||||
_ = d.dataSyncTaskApp.UpdateById(rc.MetaCtx, task)
|
||||
|
||||
if task.Status == entity.DataSyncTaskStatusEnable {
|
||||
|
||||
@@ -55,7 +55,7 @@ func (d *Instance) ReqConfs() *req.Confs {
|
||||
// Instances 获取数据库实例信息
|
||||
// @router /api/instances [get]
|
||||
func (d *Instance) Instances(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.InstanceQuery))
|
||||
queryCond := req.BindQuery[*entity.InstanceQuery](rc)
|
||||
|
||||
tags := d.tagApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
|
||||
TypePaths: collx.AsArray(tagentity.NewTypePaths(tagentity.TagTypeDbInstance, tagentity.TagTypeAuthCert)),
|
||||
@@ -90,17 +90,14 @@ func (d *Instance) Instances(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *Instance) TestConn(rc *req.Ctx) {
|
||||
form := &form.InstanceForm{}
|
||||
instance := req.BindJsonAndCopyTo[*entity.DbInstance](rc, form, new(entity.DbInstance))
|
||||
|
||||
form, instance := req.BindJsonAndCopyTo[*form.InstanceForm, *entity.DbInstance](rc)
|
||||
biz.ErrIsNil(d.instanceApp.TestConn(rc.MetaCtx, instance, form.AuthCerts[0]))
|
||||
}
|
||||
|
||||
// SaveInstance 保存数据库实例信息
|
||||
// @router /api/instances [post]
|
||||
func (d *Instance) SaveInstance(rc *req.Ctx) {
|
||||
form := &form.InstanceForm{}
|
||||
instance := req.BindJsonAndCopyTo[*entity.DbInstance](rc, form, new(entity.DbInstance))
|
||||
form, instance := req.BindJsonAndCopyTo[*form.InstanceForm, *entity.DbInstance](rc)
|
||||
|
||||
rc.ReqParam = form
|
||||
id, err := d.instanceApp.SaveDbInstance(rc.MetaCtx, &dto.SaveDbInstance{
|
||||
@@ -135,8 +132,7 @@ func (d *Instance) DeleteInstance(rc *req.Ctx) {
|
||||
|
||||
// 获取数据库实例的所有数据库名
|
||||
func (d *Instance) GetDatabaseNames(rc *req.Ctx) {
|
||||
form := &form.InstanceDbNamesForm{}
|
||||
instance := req.BindJsonAndCopyTo[*entity.DbInstance](rc, form, new(entity.DbInstance))
|
||||
form, instance := req.BindJsonAndCopyTo[*form.InstanceDbNamesForm, *entity.DbInstance](rc)
|
||||
res, err := d.instanceApp.GetDatabases(rc.MetaCtx, instance, form.AuthCert)
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = res
|
||||
|
||||
@@ -30,8 +30,7 @@ func (d *DbSql) ReqConfs() *req.Confs {
|
||||
|
||||
// @router /api/db/:dbId/sql [post]
|
||||
func (d *DbSql) SaveSql(rc *req.Ctx) {
|
||||
dbSqlForm := &form.DbSqlSaveForm{}
|
||||
req.BindJsonAndValid(rc, dbSqlForm)
|
||||
dbSqlForm := req.BindJsonAndValid[*form.DbSqlSaveForm](rc)
|
||||
rc.ReqParam = dbSqlForm
|
||||
|
||||
dbId := getDbId(rc)
|
||||
|
||||
@@ -26,7 +26,7 @@ func (d *DbSqlExec) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (d *DbSqlExec) DbSqlExecs(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.DbSqlExecQuery))
|
||||
queryCond := req.BindQuery[*entity.DbSqlExecQuery](rc)
|
||||
if statusStr := rc.Query("status"); statusStr != "" {
|
||||
queryCond.Status = collx.ArrayMap[string, int8](strings.Split(statusStr, ","), func(val string) int8 {
|
||||
return cast.ToInt8(val)
|
||||
|
||||
@@ -61,7 +61,7 @@ func (d *DbTransferTask) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (d *DbTransferTask) Tasks(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.DbTransferTaskQuery))
|
||||
queryCond := req.BindQuery[*entity.DbTransferTaskQuery](rc)
|
||||
|
||||
res, err := d.dbTransferTask.GetPageList(queryCond)
|
||||
biz.ErrIsNil(err)
|
||||
@@ -78,8 +78,7 @@ func (d *DbTransferTask) Tasks(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *DbTransferTask) SaveTask(rc *req.Ctx) {
|
||||
reqForm := &form.DbTransferTaskForm{}
|
||||
task := req.BindJsonAndCopyTo[*entity.DbTransferTask](rc, reqForm, new(entity.DbTransferTask))
|
||||
reqForm, task := req.BindJsonAndCopyTo[*form.DbTransferTaskForm, *entity.DbTransferTask](rc)
|
||||
|
||||
rc.ReqParam = reqForm
|
||||
biz.ErrIsNil(d.dbTransferTask.Save(rc.MetaCtx, task))
|
||||
@@ -98,8 +97,7 @@ func (d *DbTransferTask) DeleteTask(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *DbTransferTask) ChangeStatus(rc *req.Ctx) {
|
||||
form := &form.DbTransferTaskStatusForm{}
|
||||
task := req.BindJsonAndCopyTo[*entity.DbTransferTask](rc, form, new(entity.DbTransferTask))
|
||||
form, task := req.BindJsonAndCopyTo[*form.DbTransferTaskStatusForm, *entity.DbTransferTask](rc)
|
||||
_ = d.dbTransferTask.UpdateById(rc.MetaCtx, task)
|
||||
|
||||
task, err := d.dbTransferTask.GetById(task.Id)
|
||||
@@ -122,7 +120,7 @@ func (d *DbTransferTask) Stop(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *DbTransferTask) Files(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.DbTransferFileQuery))
|
||||
queryCond := req.BindQuery[*entity.DbTransferFileQuery](rc)
|
||||
|
||||
res, err := d.dbTransferFile.GetPageList(queryCond)
|
||||
biz.ErrIsNil(err)
|
||||
@@ -142,7 +140,7 @@ func (d *DbTransferTask) FileDel(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *DbTransferTask) FileRun(rc *req.Ctx) {
|
||||
fm := req.BindJsonAndValid(rc, &form.DbTransferFileRunForm{})
|
||||
fm := req.BindJsonAndValid[*form.DbTransferFileRunForm](rc)
|
||||
|
||||
rc.ReqParam = fm
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ func (d *dbSqlExecAppImpl) FlowBizHandle(ctx context.Context, bizHandleParam *fl
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
execSqlBizForm, err := jsonx.To(procinst.BizForm, new(FlowDbExecSqlBizForm))
|
||||
execSqlBizForm, err := jsonx.To[*FlowDbExecSqlBizForm](procinst.BizForm)
|
||||
if err != nil {
|
||||
return nil, errorx.NewBiz("failed to parse the business form information: %s", err.Error())
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (d *Instance) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (d *Instance) Instances(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.InstanceQuery))
|
||||
queryCond := req.BindQuery[*entity.InstanceQuery](rc)
|
||||
|
||||
// 只查询实例,兼容没有录入密码的实例
|
||||
instTags := d.tagApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
|
||||
@@ -92,8 +92,7 @@ func (d *Instance) Instances(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *Instance) TestConn(rc *req.Ctx) {
|
||||
fm := &form.InstanceForm{}
|
||||
instance := req.BindJsonAndCopyTo[*entity.EsInstance](rc, fm, new(entity.EsInstance))
|
||||
fm, instance := req.BindJsonAndCopyTo[*form.InstanceForm, *entity.EsInstance](rc)
|
||||
|
||||
var ac *tagentity.ResourceAuthCert
|
||||
if len(fm.AuthCerts) > 0 {
|
||||
@@ -105,8 +104,7 @@ func (d *Instance) TestConn(rc *req.Ctx) {
|
||||
rc.ResData = res
|
||||
}
|
||||
func (d *Instance) SaveInstance(rc *req.Ctx) {
|
||||
fm := &form.InstanceForm{}
|
||||
instance := req.BindJsonAndCopyTo[*entity.EsInstance](rc, fm, new(entity.EsInstance))
|
||||
fm, instance := req.BindJsonAndCopyTo[*form.InstanceForm, *entity.EsInstance](rc)
|
||||
|
||||
rc.ReqParam = fm
|
||||
id, err := d.inst.SaveInst(rc.MetaCtx, &dto.SaveEsInstance{
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
)
|
||||
|
||||
type InstanceForm struct {
|
||||
Id uint64 `json:"id"`
|
||||
Name string `binding:"required" json:"name"`
|
||||
Host string `binding:"required" json:"host"`
|
||||
Port int `binding:"required" json:"port"`
|
||||
Version string `json:"version"`
|
||||
Remark string `json:"remark"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"`
|
||||
Id uint64 `json:"id"`
|
||||
Name string `binding:"required" json:"name"`
|
||||
Host string `binding:"required" json:"host"`
|
||||
Port int `binding:"required" json:"port"`
|
||||
Version string `json:"version"`
|
||||
Remark *string `json:"remark"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"`
|
||||
|
||||
AuthCerts []*tagentity.ResourceAuthCert `json:"authCerts"` // 资产授权凭证信息列表
|
||||
TagCodePaths []string `binding:"required" json:"tagCodePaths"`
|
||||
|
||||
@@ -9,16 +9,17 @@ type InstanceListVO struct {
|
||||
tagentity.AuthCerts // 授权凭证信息
|
||||
tagentity.ResourceTags
|
||||
|
||||
Id *int64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name *string `json:"name"`
|
||||
Host *string `json:"host"`
|
||||
Port *int `json:"port"`
|
||||
Version *string `json:"version"`
|
||||
Id *int64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name *string `json:"name"`
|
||||
Host *string `json:"host"`
|
||||
Port *int `json:"port"`
|
||||
Version *string `json:"version"`
|
||||
Remark *string `json:"remark"`
|
||||
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
Creator *string `json:"creator"`
|
||||
CreatorId *int64 `json:"creatorId"`
|
||||
|
||||
UpdateTime *time.Time `json:"updateTime"`
|
||||
Modifier *string `json:"modifier"`
|
||||
ModifierId *int64 `json:"modifierId"`
|
||||
|
||||
@@ -8,14 +8,14 @@ import (
|
||||
type EsInstance struct {
|
||||
model.Model
|
||||
|
||||
Code string `json:"code" gorm:"size:32;not null;"`
|
||||
Name string `json:"name" gorm:"size:32;not null;"`
|
||||
Host string `json:"host" gorm:"size:255;not null;"`
|
||||
Port int `json:"port"`
|
||||
Network string `json:"network" gorm:"size:20;"`
|
||||
Version string `json:"version" gorm:"size:50;"`
|
||||
AuthCertName string `json:"authCertName" gorm:"size:255;"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"` // ssh隧道机器id
|
||||
Code string `json:"code" gorm:"size:32;not null;"`
|
||||
Name string `json:"name" gorm:"size:32;not null;"`
|
||||
Host string `json:"host" gorm:"size:255;not null;"`
|
||||
Port int `json:"port"`
|
||||
Network string `json:"network" gorm:"size:20;"`
|
||||
Version string `json:"version" gorm:"size:50;"`
|
||||
Remark *string `json:"remark" gorm:"size:255;"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"` // ssh隧道机器id
|
||||
}
|
||||
|
||||
func (d *EsInstance) TableName() string {
|
||||
|
||||
@@ -48,7 +48,7 @@ func (p *Procdef) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (p *Procdef) GetProcdefPage(rc *req.Ctx) {
|
||||
cond, page := req.BindQueryAndPage(rc, new(entity.Procdef))
|
||||
cond, page := req.BindQueryAndPage[*entity.Procdef](rc)
|
||||
|
||||
res, err := p.procdefApp.GetPageList(cond, page)
|
||||
biz.ErrIsNil(err)
|
||||
@@ -87,8 +87,7 @@ func (p *Procdef) GetProcdef(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (a *Procdef) Save(rc *req.Ctx) {
|
||||
form := &form.Procdef{}
|
||||
procdef := req.BindJsonAndCopyTo(rc, form, new(entity.Procdef))
|
||||
form, procdef := req.BindJsonAndCopyTo[*form.Procdef, *entity.Procdef](rc)
|
||||
rc.ReqParam = form
|
||||
biz.ErrIsNil(a.procdefApp.SaveProcdef(rc.MetaCtx, &dto.SaveProcdef{
|
||||
Procdef: procdef,
|
||||
@@ -98,7 +97,7 @@ func (a *Procdef) Save(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (a *Procdef) SaveFlowDef(rc *req.Ctx) {
|
||||
form := req.BindJsonAndValid(rc, &form.ProcdefFlow{})
|
||||
form := req.BindJsonAndValid[*form.ProcdefFlow](rc)
|
||||
rc.ReqParam = form
|
||||
|
||||
biz.ErrIsNil(a.procdefApp.SaveFlowDef(rc.MetaCtx, &dto.SaveFlowDef{
|
||||
|
||||
@@ -35,7 +35,7 @@ func (p *Procinst) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (p *Procinst) GetProcinstPage(rc *req.Ctx) {
|
||||
cond := req.BindQuery(rc, new(entity.ProcinstQuery))
|
||||
cond := req.BindQuery[*entity.ProcinstQuery](rc)
|
||||
// 非管理员只能获取自己申请的流程
|
||||
if laId := rc.GetLoginAccount().Id; laId != consts.AdminId {
|
||||
cond.CreatorId = laId
|
||||
@@ -47,8 +47,7 @@ func (p *Procinst) GetProcinstPage(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *Procinst) ProcinstStart(rc *req.Ctx) {
|
||||
startForm := new(form.ProcinstStart)
|
||||
req.BindJsonAndValid(rc, startForm)
|
||||
startForm := req.BindJsonAndValid[*form.ProcinstStart](rc)
|
||||
_, err := p.procinstApp.StartProc(rc.MetaCtx, startForm.ProcdefId, &dto.StarProc{
|
||||
BizType: startForm.BizType,
|
||||
BizForm: jsonx.ToStr(startForm.BizForm),
|
||||
|
||||
@@ -41,7 +41,7 @@ func (p *ProcinstTask) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (p *ProcinstTask) GetTasks(rc *req.Ctx) {
|
||||
instTaskQuery := req.BindQuery(rc, new(entity.ProcinstTaskQuery))
|
||||
instTaskQuery := req.BindQuery[*entity.ProcinstTaskQuery](rc)
|
||||
if laId := rc.GetLoginAccount().Id; laId != consts.AdminId {
|
||||
// 赋值操作人为当前登录账号
|
||||
instTaskQuery.Assignee = fmt.Sprintf("%d", rc.GetLoginAccount().Id)
|
||||
@@ -74,7 +74,7 @@ func (p *ProcinstTask) GetTasks(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *ProcinstTask) PassTask(rc *req.Ctx) {
|
||||
auditForm := req.BindJsonAndValid(rc, new(form.ProcinstTaskAudit))
|
||||
auditForm := req.BindJsonAndValid[*form.ProcinstTaskAudit](rc)
|
||||
rc.ReqParam = auditForm
|
||||
|
||||
la := rc.GetLoginAccount()
|
||||
@@ -84,7 +84,7 @@ func (p *ProcinstTask) PassTask(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *ProcinstTask) RejectTask(rc *req.Ctx) {
|
||||
auditForm := req.BindJsonAndValid(rc, new(form.ProcinstTaskAudit))
|
||||
auditForm := req.BindJsonAndValid[*form.ProcinstTaskAudit](rc)
|
||||
rc.ReqParam = auditForm
|
||||
|
||||
la := rc.GetLoginAccount()
|
||||
@@ -94,7 +94,7 @@ func (p *ProcinstTask) RejectTask(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *ProcinstTask) BackTask(rc *req.Ctx) {
|
||||
auditForm := req.BindJsonAndValid(rc, new(form.ProcinstTaskAudit))
|
||||
auditForm := req.BindJsonAndValid[*form.ProcinstTaskAudit](rc)
|
||||
rc.ReqParam = auditForm
|
||||
biz.ErrIsNil(p.procinstTaskApp.BackTask(rc.MetaCtx, dto.UserTaskOp{TaskId: auditForm.Id, Remark: auditForm.Remark}))
|
||||
}
|
||||
|
||||
@@ -104,7 +104,9 @@ func (e *executionAppImpl) MoveTo(ctx *ExecutionCtx, nextNode *entity.FlowNode)
|
||||
}
|
||||
|
||||
// 记录当前节点结束
|
||||
e.hisProcinstOpApp.RecordEnd(ctx, "copmpleted")
|
||||
if err := e.hisProcinstOpApp.RecordEnd(ctx, "copmpleted"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 下一个节点为空,说明流程已结束
|
||||
if nextNode == nil {
|
||||
@@ -163,7 +165,9 @@ func (e *executionAppImpl) executeNode(ctx *ExecutionCtx) error {
|
||||
}
|
||||
|
||||
// 节点开始操作记录
|
||||
e.hisProcinstOpApp.RecordStart(ctx)
|
||||
if err := e.hisProcinstOpApp.RecordStart(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 执行节点逻辑
|
||||
return node.Execute(ctx)
|
||||
|
||||
@@ -61,7 +61,7 @@ func (p *Procdef) GetFlowDef() *FlowDef {
|
||||
if p.FlowDef == "" {
|
||||
return nil
|
||||
}
|
||||
flow, err := jsonx.To(p.FlowDef, new(FlowDef))
|
||||
flow, err := jsonx.To[*FlowDef](p.FlowDef)
|
||||
if err != nil {
|
||||
logx.ErrorTrace("parse flow def failed", err)
|
||||
return flow
|
||||
|
||||
@@ -43,7 +43,7 @@ func (a *Procinst) SetEnd() {
|
||||
|
||||
// GetProcdefFlow 获取流程定义信息
|
||||
func (p *Procinst) GetFlowDef() *FlowDef {
|
||||
flow, err := jsonx.To(p.FlowDef, new(FlowDef))
|
||||
flow, err := jsonx.To[*FlowDef](p.FlowDef)
|
||||
if err != nil {
|
||||
logx.ErrorTrace("parse procdef flow failed", err)
|
||||
return flow
|
||||
|
||||
@@ -50,12 +50,12 @@ type MachineCronJobForm struct {
|
||||
}
|
||||
|
||||
type MachineCmdConfForm struct {
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Cmds []string `json:"cmds"` // 命令配置
|
||||
Status int8 `json:"execCmds"` // 状态
|
||||
Stratege string `json:"stratege"` // 策略,空禁用
|
||||
Remark string `json:"remark"` // 备注
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Cmds model.Slice[string] `json:"cmds"` // 命令配置
|
||||
Status int8 `json:"execCmds"` // 状态
|
||||
Stratege string `json:"stratege"` // 策略,空禁用
|
||||
Remark string `json:"remark"` // 备注
|
||||
|
||||
CodePaths []string `json:"codePaths"`
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func (m *Machine) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (m *Machine) Machines(rc *req.Ctx) {
|
||||
condition := req.BindQuery(rc, new(entity.MachineQuery))
|
||||
condition := req.BindQuery[*entity.MachineQuery](rc)
|
||||
|
||||
tags := m.tagTreeApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
|
||||
TypePaths: collx.AsArray(tagentity.NewTypePaths(tagentity.TagTypeMachine, tagentity.TagTypeAuthCert)),
|
||||
@@ -143,8 +143,7 @@ func (m *Machine) MachineStats(rc *req.Ctx) {
|
||||
|
||||
// 保存机器信息
|
||||
func (m *Machine) SaveMachine(rc *req.Ctx) {
|
||||
machineForm := new(form.MachineForm)
|
||||
me := req.BindJsonAndCopyTo(rc, machineForm, new(entity.Machine))
|
||||
machineForm, me := req.BindJsonAndCopyTo[*form.MachineForm, *entity.Machine](rc)
|
||||
|
||||
rc.ReqParam = machineForm
|
||||
|
||||
@@ -156,8 +155,7 @@ func (m *Machine) SaveMachine(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Machine) TestConn(rc *req.Ctx) {
|
||||
machineForm := new(form.MachineForm)
|
||||
me := req.BindJsonAndCopyTo(rc, machineForm, new(entity.Machine))
|
||||
machineForm, me := req.BindJsonAndCopyTo[*form.MachineForm, *entity.Machine](rc)
|
||||
// 测试连接
|
||||
biz.ErrIsNilAppendErr(m.machineApp.TestConn(rc.MetaCtx, me, machineForm.AuthCerts[0]), "connection error: %s")
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (mcc *MachineCmdConf) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (m *MachineCmdConf) MachineCmdConfs(rc *req.Ctx) {
|
||||
cond := req.BindQuery(rc, new(entity.MachineCmdConf))
|
||||
cond := req.BindQuery[*entity.MachineCmdConf](rc)
|
||||
|
||||
var vos []*vo.MachineCmdConfVO
|
||||
err := m.machineCmdConfApp.ListByCondToAny(cond, &vos)
|
||||
@@ -47,8 +47,7 @@ func (m *MachineCmdConf) MachineCmdConfs(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineCmdConf) Save(rc *req.Ctx) {
|
||||
cmdForm := new(form.MachineCmdConfForm)
|
||||
mcj := req.BindJsonAndCopyTo[*entity.MachineCmdConf](rc, cmdForm, new(entity.MachineCmdConf))
|
||||
cmdForm, mcj := req.BindJsonAndCopyTo[*form.MachineCmdConfForm, *entity.MachineCmdConf](rc)
|
||||
rc.ReqParam = cmdForm
|
||||
|
||||
err := m.machineCmdConfApp.SaveCmdConf(rc.MetaCtx, &dto.SaveMachineCmdConf{
|
||||
|
||||
@@ -43,7 +43,7 @@ func (mcj *MachineCronJob) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (m *MachineCronJob) MachineCronJobs(rc *req.Ctx) {
|
||||
cond, pageParam := req.BindQueryAndPage(rc, new(entity.MachineCronJob))
|
||||
cond, pageParam := req.BindQueryAndPage[*entity.MachineCronJob](rc)
|
||||
|
||||
pageRes, err := m.machineCronJobApp.GetPageList(cond, pageParam)
|
||||
biz.ErrIsNil(err)
|
||||
@@ -62,8 +62,7 @@ func (m *MachineCronJob) MachineCronJobs(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineCronJob) Save(rc *req.Ctx) {
|
||||
jobForm := new(form.MachineCronJobForm)
|
||||
mcj := req.BindJsonAndCopyTo[*entity.MachineCronJob](rc, jobForm, new(entity.MachineCronJob))
|
||||
jobForm, mcj := req.BindJsonAndCopyTo[*form.MachineCronJobForm, *entity.MachineCronJob](rc)
|
||||
rc.ReqParam = jobForm
|
||||
|
||||
err := m.machineCronJobApp.SaveMachineCronJob(rc.MetaCtx, &dto.SaveMachineCronJob{
|
||||
@@ -90,7 +89,7 @@ func (m *MachineCronJob) RunCronJob(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineCronJob) CronJobExecs(rc *req.Ctx) {
|
||||
cond, pageParam := req.BindQueryAndPage[*entity.MachineCronJobExec](rc, new(entity.MachineCronJobExec))
|
||||
cond, pageParam := req.BindQueryAndPage[*entity.MachineCronJobExec](rc)
|
||||
res, err := m.machineCronJobApp.GetExecPageList(cond, pageParam)
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = res
|
||||
|
||||
@@ -93,8 +93,7 @@ func (m *MachineFile) MachineFiles(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) SaveMachineFiles(rc *req.Ctx) {
|
||||
fileForm := new(form.MachineFileForm)
|
||||
entity := req.BindJsonAndCopyTo[*entity.MachineFile](rc, fileForm, new(entity.MachineFile))
|
||||
fileForm, entity := req.BindJsonAndCopyTo[*form.MachineFileForm, *entity.MachineFile](rc)
|
||||
|
||||
rc.ReqParam = fileForm
|
||||
biz.ErrIsNil(m.machineFileApp.Save(rc.MetaCtx, entity))
|
||||
@@ -107,7 +106,7 @@ func (m *MachineFile) DeleteFile(rc *req.Ctx) {
|
||||
/*** sftp相关操作 */
|
||||
|
||||
func (m *MachineFile) CreateFile(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid(rc, new(form.CreateFileForm))
|
||||
opForm := req.BindJsonAndValid[*form.CreateFileForm](rc)
|
||||
path := opForm.Path
|
||||
|
||||
attrs := collx.Kvs("path", path)
|
||||
@@ -126,7 +125,7 @@ func (m *MachineFile) CreateFile(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) ReadFileContent(rc *req.Ctx) {
|
||||
opForm := req.BindQuery(rc, new(dto.MachineFileOp))
|
||||
opForm := req.BindQuery[*dto.MachineFileOp](rc)
|
||||
readPath := opForm.Path
|
||||
ctx := rc.MetaCtx
|
||||
|
||||
@@ -158,7 +157,7 @@ func (m *MachineFile) ReadFileContent(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) DownloadFile(rc *req.Ctx) {
|
||||
opForm := req.BindQuery(rc, new(dto.MachineFileOp))
|
||||
opForm := req.BindQuery[*dto.MachineFileOp](rc)
|
||||
|
||||
readPath := opForm.Path
|
||||
|
||||
@@ -186,7 +185,7 @@ func (m *MachineFile) DownloadFile(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) GetDirEntry(rc *req.Ctx) {
|
||||
opForm := req.BindQuery(rc, new(dto.MachineFileOp))
|
||||
opForm := req.BindQuery[*dto.MachineFileOp](rc)
|
||||
readPath := opForm.Path
|
||||
rc.ReqParam = fmt.Sprintf("path: %s", readPath)
|
||||
|
||||
@@ -225,7 +224,7 @@ func (m *MachineFile) GetDirEntry(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) GetDirSize(rc *req.Ctx) {
|
||||
opForm := req.BindQuery(rc, new(dto.MachineFileOp))
|
||||
opForm := req.BindQuery[*dto.MachineFileOp](rc)
|
||||
|
||||
size, err := m.machineFileApp.GetDirSize(rc.MetaCtx, opForm)
|
||||
biz.ErrIsNil(err)
|
||||
@@ -233,14 +232,14 @@ func (m *MachineFile) GetDirSize(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) GetFileStat(rc *req.Ctx) {
|
||||
opForm := req.BindQuery(rc, new(dto.MachineFileOp))
|
||||
opForm := req.BindQuery[*dto.MachineFileOp](rc)
|
||||
res, err := m.machineFileApp.FileStat(rc.MetaCtx, opForm)
|
||||
biz.ErrIsNil(err, res)
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *MachineFile) WriteFileContent(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid(rc, new(form.WriteFileContentForm))
|
||||
opForm := req.BindJsonAndValid[*form.WriteFileContentForm](rc)
|
||||
path := opForm.Path
|
||||
|
||||
mi, err := m.machineFileApp.WriteFileContent(rc.MetaCtx, opForm.MachineFileOp, []byte(opForm.Content))
|
||||
@@ -401,7 +400,7 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) RemoveFile(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid(rc, new(form.RemoveFileForm))
|
||||
opForm := req.BindJsonAndValid[*form.RemoveFileForm](rc)
|
||||
|
||||
mi, err := m.machineFileApp.RemoveFile(rc.MetaCtx, opForm.MachineFileOp, opForm.Paths...)
|
||||
rc.ReqParam = collx.Kvs("machine", mi, "path", opForm)
|
||||
@@ -409,21 +408,21 @@ func (m *MachineFile) RemoveFile(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) CopyFile(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid(rc, new(form.CopyFileForm))
|
||||
opForm := req.BindJsonAndValid[*form.CopyFileForm](rc)
|
||||
mi, err := m.machineFileApp.Copy(rc.MetaCtx, opForm.MachineFileOp, opForm.ToPath, opForm.Paths...)
|
||||
biz.ErrIsNilAppendErr(err, "file copy error: %s")
|
||||
rc.ReqParam = collx.Kvs("machine", mi, "cp", opForm)
|
||||
}
|
||||
|
||||
func (m *MachineFile) MvFile(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid(rc, new(form.CopyFileForm))
|
||||
opForm := req.BindJsonAndValid[*form.CopyFileForm](rc)
|
||||
mi, err := m.machineFileApp.Mv(rc.MetaCtx, opForm.MachineFileOp, opForm.ToPath, opForm.Paths...)
|
||||
rc.ReqParam = collx.Kvs("machine", mi, "mv", opForm)
|
||||
biz.ErrIsNilAppendErr(err, "file move error: %s")
|
||||
}
|
||||
|
||||
func (m *MachineFile) Rename(rc *req.Ctx) {
|
||||
renameForm := req.BindJsonAndValid(rc, new(form.RenameForm))
|
||||
renameForm := req.BindJsonAndValid[*form.RenameForm](rc)
|
||||
mi, err := m.machineFileApp.Rename(rc.MetaCtx, renameForm.MachineFileOp, renameForm.Newname)
|
||||
rc.ReqParam = collx.Kvs("machine", mi, "rename", renameForm)
|
||||
biz.ErrIsNilAppendErr(err, "file rename error: %s")
|
||||
|
||||
@@ -46,8 +46,7 @@ func (m *MachineScript) MachineScripts(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineScript) SaveMachineScript(rc *req.Ctx) {
|
||||
form := new(form.MachineScriptForm)
|
||||
machineScript := req.BindJsonAndCopyTo(rc, form, new(entity.MachineScript))
|
||||
form, machineScript := req.BindJsonAndCopyTo[*form.MachineScriptForm, *entity.MachineScript](rc)
|
||||
|
||||
rc.ReqParam = form
|
||||
biz.ErrIsNil(m.machineScriptApp.Save(rc.MetaCtx, machineScript))
|
||||
|
||||
@@ -111,10 +111,10 @@ type MachineCmdConfVO struct {
|
||||
model.Model
|
||||
|
||||
Name string `json:"name"`
|
||||
Cmds model.Slice[string] `json:"cmds"` // 命令配置
|
||||
Status int8 `json:"execCmds"` // 状态
|
||||
Stratege string `json:"stratege"` // 策略,空禁用
|
||||
Remark string `json:"remark"` // 备注
|
||||
Cmds model.Slice[string] `json:"cmds" gorm:"type:varchar"` // 命令配置,要加gorm标签才会正确解析model.Slice
|
||||
Status int8 `json:"execCmds"` // 状态
|
||||
Stratege string `json:"stratege"` // 策略,空禁用
|
||||
Remark string `json:"remark"` // 备注
|
||||
}
|
||||
|
||||
func (mcc *MachineCmdConfVO) GetRelateId() uint64 {
|
||||
|
||||
@@ -20,5 +20,5 @@ func GetMachineStats(machineId uint64) (*mcm.Stats, error) {
|
||||
if cacheStr == "" {
|
||||
return nil, errors.New("不存在该值")
|
||||
}
|
||||
return jsonx.To(cacheStr, new(mcm.Stats))
|
||||
return jsonx.To[*mcm.Stats](cacheStr)
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func (ma *Mongo) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (m *Mongo) Mongos(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.MongoQuery))
|
||||
queryCond := req.BindQuery[*entity.MongoQuery](rc)
|
||||
|
||||
// 不存在可访问标签id,即没有可操作数据
|
||||
tags := m.tagTreeApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
|
||||
@@ -95,14 +95,12 @@ func (m *Mongo) Mongos(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) TestConn(rc *req.Ctx) {
|
||||
form := &form.Mongo{}
|
||||
mongo := req.BindJsonAndCopyTo[*entity.Mongo](rc, form, new(entity.Mongo))
|
||||
_, mongo := req.BindJsonAndCopyTo[*form.Mongo, *entity.Mongo](rc)
|
||||
biz.ErrIsNilAppendErr(m.mongoApp.TestConn(mongo), "connection error: %s")
|
||||
}
|
||||
|
||||
func (m *Mongo) Save(rc *req.Ctx) {
|
||||
form := &form.Mongo{}
|
||||
mongo := req.BindJsonAndCopyTo[*entity.Mongo](rc, form, new(entity.Mongo))
|
||||
form, mongo := req.BindJsonAndCopyTo[*form.Mongo, *entity.Mongo](rc)
|
||||
|
||||
// 密码脱敏记录日志
|
||||
form.Uri = func(str string) string {
|
||||
@@ -148,8 +146,7 @@ func (m *Mongo) Collections(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) RunCommand(rc *req.Ctx) {
|
||||
commandForm := new(form.MongoRunCommand)
|
||||
req.BindJsonAndValid(rc, commandForm)
|
||||
commandForm := req.BindJsonAndValid[*form.MongoRunCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
@@ -179,7 +176,7 @@ func (m *Mongo) RunCommand(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) FindCommand(rc *req.Ctx) {
|
||||
commandForm := req.BindJsonAndValid(rc, new(form.MongoFindCommand))
|
||||
commandForm := req.BindJsonAndValid[*form.MongoFindCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
@@ -214,7 +211,7 @@ func (m *Mongo) FindCommand(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) UpdateByIdCommand(rc *req.Ctx) {
|
||||
commandForm := req.BindJsonAndValid(rc, new(form.MongoUpdateByIdCommand))
|
||||
commandForm := req.BindJsonAndValid[*form.MongoUpdateByIdCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
@@ -238,7 +235,7 @@ func (m *Mongo) UpdateByIdCommand(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) DeleteByIdCommand(rc *req.Ctx) {
|
||||
commandForm := req.BindJsonAndValid(rc, new(form.MongoUpdateByIdCommand))
|
||||
commandForm := req.BindJsonAndValid[*form.MongoUpdateByIdCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
@@ -261,7 +258,7 @@ func (m *Mongo) DeleteByIdCommand(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) InsertOneCommand(rc *req.Ctx) {
|
||||
commandForm := req.BindJsonAndValid(rc, new(form.MongoInsertCommand))
|
||||
commandForm := req.BindJsonAndValid[*form.MongoInsertCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
@@ -36,9 +36,8 @@ func (m *MsgChannel) GetMsgChannels(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MsgChannel) SaveMsgChannels(rc *req.Ctx) {
|
||||
form := &form.MsgChannel{}
|
||||
form, channel := req.BindJsonAndCopyTo[*form.MsgChannel, *entity.MsgChannel](rc)
|
||||
rc.ReqParam = form
|
||||
channel := req.BindJsonAndCopyTo(rc, form, new(entity.MsgChannel))
|
||||
err := m.msgChannelApp.SaveChannel(rc.MetaCtx, channel)
|
||||
biz.ErrIsNil(err)
|
||||
}
|
||||
|
||||
@@ -57,9 +57,8 @@ func (m *MsgTmpl) GetMsgTmplChannels(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MsgTmpl) SaveMsgTmpl(rc *req.Ctx) {
|
||||
form := &form.MsgTmpl{}
|
||||
form, channel := req.BindJsonAndCopyTo[*form.MsgTmpl, *dto.MsgTmplSave](rc)
|
||||
rc.ReqParam = form
|
||||
channel := req.BindJsonAndCopyTo(rc, form, new(dto.MsgTmplSave))
|
||||
biz.ErrIsNil(m.msgTmplApp.SaveTmpl(rc.MetaCtx, channel))
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ func (m *MsgTmpl) DelMsgTmpls(rc *req.Ctx) {
|
||||
|
||||
func (m *MsgTmpl) SendMsg(rc *req.Ctx) {
|
||||
code := rc.PathParam("code")
|
||||
form := req.BindJsonAndValid(rc, new(form.SendMsg))
|
||||
form := req.BindJsonAndValid[*form.SendMsg](rc)
|
||||
|
||||
rc.ReqParam = form
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func (r *Redis) RunCmd(rc *req.Ctx) {
|
||||
var cmdReq form.RunCmdForm
|
||||
runCmdParam := req.BindJsonAndCopyTo(rc, &cmdReq, new(dto.RunCmd))
|
||||
cmdReq, runCmdParam := req.BindJsonAndCopyTo[*form.RunCmdForm, *dto.RunCmd](rc)
|
||||
biz.IsTrue(len(cmdReq.Cmd) > 0, "redis cmd cannot be empty")
|
||||
|
||||
redisConn := r.getRedisConn(rc)
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
func (r *Redis) ScanKeys(rc *req.Ctx) {
|
||||
ri := r.getRedisConn(rc)
|
||||
|
||||
form := req.BindJsonAndValid(rc, new(form.RedisScanForm))
|
||||
form := req.BindJsonAndValid[*form.RedisScanForm](rc)
|
||||
|
||||
cmd := ri.GetCmdable()
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -60,7 +60,7 @@ func (rs *Redis) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (r *Redis) RedisList(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.RedisQuery))
|
||||
queryCond := req.BindQuery[*entity.RedisQuery](rc)
|
||||
|
||||
// 不存在可访问标签id,即没有可操作数据
|
||||
tags := r.tagApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
|
||||
@@ -87,8 +87,7 @@ func (r *Redis) RedisList(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (r *Redis) TestConn(rc *req.Ctx) {
|
||||
form := &form.Redis{}
|
||||
redis := req.BindJsonAndCopyTo[*entity.Redis](rc, form, new(entity.Redis))
|
||||
form, redis := req.BindJsonAndCopyTo[*form.Redis, *entity.Redis](rc)
|
||||
|
||||
authCert := &tagentity.ResourceAuthCert{
|
||||
Username: form.Username,
|
||||
@@ -110,8 +109,7 @@ func (r *Redis) TestConn(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (r *Redis) Save(rc *req.Ctx) {
|
||||
form := &form.Redis{}
|
||||
redis := req.BindJsonAndCopyTo[*entity.Redis](rc, form, new(entity.Redis))
|
||||
form, redis := req.BindJsonAndCopyTo[*form.Redis, *entity.Redis](rc)
|
||||
|
||||
redisParam := &dto.SaveRedis{
|
||||
Redis: redis,
|
||||
|
||||
@@ -253,7 +253,7 @@ func (r *redisAppImpl) FlowBizHandle(ctx context.Context, bizHandleParam *flowap
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
runCmdParam, err := jsonx.To(procinst.BizForm, new(FlowRedisRunCmdBizForm))
|
||||
runCmdParam, err := jsonx.To[*FlowRedisRunCmdBizForm](procinst.BizForm)
|
||||
if err != nil {
|
||||
return nil, errorx.NewBiz("failed to parse the business form information: %s", err.Error())
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func (a *Account) GetPermissions(rc *req.Ctx) {
|
||||
func (a *Account) ChangePassword(rc *req.Ctx) {
|
||||
ctx := rc.MetaCtx
|
||||
|
||||
form := req.BindJsonAndValid(rc, new(form.AccountChangePasswordForm))
|
||||
form := req.BindJsonAndValid[*form.AccountChangePasswordForm](rc)
|
||||
|
||||
originOldPwd, err := utils.DefaultRsaDecrypt(form.OldPassword, true)
|
||||
biz.ErrIsNilAppendErr(err, "Wrong to decrypt old password: %s")
|
||||
@@ -145,9 +145,10 @@ func (a *Account) AccountInfo(rc *req.Ctx) {
|
||||
|
||||
// 更新个人账号信息
|
||||
func (a *Account) UpdateAccount(rc *req.Ctx) {
|
||||
updateAccount := req.BindJsonAndCopyTo[*entity.Account](rc, new(form.AccountUpdateForm), new(entity.Account))
|
||||
form, updateAccount := req.BindJsonAndCopyTo[*form.AccountUpdateForm, *entity.Account](rc)
|
||||
// 账号id为登录者账号
|
||||
updateAccount.Id = rc.GetLoginAccount().Id
|
||||
rc.ReqParam = form
|
||||
|
||||
ctx := rc.MetaCtx
|
||||
if updateAccount.Password != "" {
|
||||
@@ -210,8 +211,7 @@ func (a *Account) AccountDetail(rc *req.Ctx) {
|
||||
|
||||
// @router /accounts
|
||||
func (a *Account) SaveAccount(rc *req.Ctx) {
|
||||
form := &form.AccountCreateForm{}
|
||||
account := req.BindJsonAndCopyTo(rc, form, new(entity.Account))
|
||||
form, account := req.BindJsonAndCopyTo[*form.AccountCreateForm, *entity.Account](rc)
|
||||
|
||||
form.Password = "*****"
|
||||
rc.ReqParam = form
|
||||
@@ -307,7 +307,7 @@ func (a *Account) AccountResources(rc *req.Ctx) {
|
||||
|
||||
// 关联账号角色
|
||||
func (a *Account) RelateRole(rc *req.Ctx) {
|
||||
form := req.BindJsonAndValid(rc, new(form.AccountRoleForm))
|
||||
form := req.BindJsonAndValid[*form.AccountRoleForm](rc)
|
||||
rc.ReqParam = form
|
||||
biz.ErrIsNil(a.roleApp.RelateAccountRole(rc.MetaCtx, form.Id, form.RoleId, consts.AccountRoleRelateType(form.RelateType)))
|
||||
}
|
||||
|
||||
@@ -55,8 +55,7 @@ func (c *Config) GetConfigValueByKey(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (c *Config) SaveConfig(rc *req.Ctx) {
|
||||
form := &form.ConfigForm{}
|
||||
config := req.BindJsonAndCopyTo(rc, form, new(entity.Config))
|
||||
form, config := req.BindJsonAndCopyTo[*form.ConfigForm, *entity.Config](rc)
|
||||
rc.ReqParam = form
|
||||
biz.ErrIsNil(c.configApp.Save(rc.MetaCtx, config))
|
||||
}
|
||||
|
||||
@@ -50,8 +50,7 @@ func (r *Resource) GetById(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (r *Resource) SaveResource(rc *req.Ctx) {
|
||||
form := new(form.ResourceForm)
|
||||
entity := req.BindJsonAndCopyTo(rc, form, new(entity.Resource))
|
||||
form, entity := req.BindJsonAndCopyTo[*form.ResourceForm, *entity.Resource](rc)
|
||||
|
||||
rc.ReqParam = form
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ func (r *Role) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (r *Role) Roles(rc *req.Ctx) {
|
||||
cond := req.BindQuery(rc, new(entity.RoleQuery))
|
||||
cond := req.BindQuery[*entity.RoleQuery](rc)
|
||||
|
||||
notIdsStr := rc.Query("notIds")
|
||||
if notIdsStr != "" {
|
||||
@@ -61,8 +61,7 @@ func (r *Role) Roles(rc *req.Ctx) {
|
||||
|
||||
// 保存角色信息
|
||||
func (r *Role) SaveRole(rc *req.Ctx) {
|
||||
form := &form.RoleForm{}
|
||||
role := req.BindJsonAndCopyTo(rc, form, new(entity.Role))
|
||||
form, role := req.BindJsonAndCopyTo[*form.RoleForm, *entity.Role](rc)
|
||||
rc.ReqParam = form
|
||||
|
||||
r.roleApp.SaveRole(rc.MetaCtx, role)
|
||||
@@ -93,8 +92,7 @@ func (r *Role) RoleResource(rc *req.Ctx) {
|
||||
|
||||
// 保存角色资源
|
||||
func (r *Role) SaveResource(rc *req.Ctx) {
|
||||
var form form.RoleResourceForm
|
||||
req.BindJsonAndValid(rc, &form)
|
||||
form := req.BindJsonAndValid[*form.RoleResourceForm](rc)
|
||||
rc.ReqParam = form
|
||||
|
||||
// 将,拼接的字符串进行切割并转换
|
||||
@@ -107,7 +105,7 @@ func (r *Role) SaveResource(rc *req.Ctx) {
|
||||
|
||||
// 查看角色关联的用户
|
||||
func (r *Role) RoleAccount(rc *req.Ctx) {
|
||||
cond := req.BindQuery(rc, new(entity.RoleAccountQuery))
|
||||
cond := req.BindQuery[*entity.RoleAccountQuery](rc)
|
||||
cond.RoleId = uint64(rc.PathParamInt("id"))
|
||||
res, err := r.roleApp.GetRoleAccountPage(cond)
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
@@ -21,7 +21,7 @@ func (s *Syslog) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (r *Syslog) Syslogs(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.SysLogQuery))
|
||||
queryCond := req.BindQuery[*entity.SysLogQuery](rc)
|
||||
res, err := r.syslogApp.GetPageList(queryCond, "create_time DESC")
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = res
|
||||
|
||||
@@ -72,8 +72,7 @@ func (r *ResourceAuthCert) GetCompleteAuthCert(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (c *ResourceAuthCert) SaveAuthCert(rc *req.Ctx) {
|
||||
acForm := &form.AuthCertForm{}
|
||||
ac := req.BindJsonAndCopyTo(rc, acForm, new(entity.ResourceAuthCert))
|
||||
acForm, ac := req.BindJsonAndCopyTo[*form.AuthCertForm, *entity.ResourceAuthCert](rc)
|
||||
|
||||
// 脱敏记录日志
|
||||
acForm.Ciphertext = "***"
|
||||
|
||||
@@ -119,8 +119,7 @@ func (p *TagTree) ListByQuery(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *TagTree) SaveTagTree(rc *req.Ctx) {
|
||||
tagForm := &form.TagTree{}
|
||||
tagTree := req.BindJsonAndCopyTo(rc, tagForm, new(entity.TagTree))
|
||||
tagForm, tagTree := req.BindJsonAndCopyTo[*form.TagTree, *entity.TagTree](rc)
|
||||
|
||||
rc.ReqParam = fmt.Sprintf("tagTreeId: %d, tagName: %s, code: %s", tagTree.Id, tagTree.Name, tagTree.Code)
|
||||
|
||||
@@ -132,8 +131,7 @@ func (p *TagTree) DelTagTree(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *TagTree) MovingTag(rc *req.Ctx) {
|
||||
movingForm := &form.MovingTag{}
|
||||
req.BindJsonAndValid(rc, movingForm)
|
||||
movingForm := req.BindJsonAndValid[*form.MovingTag](rc)
|
||||
rc.ReqParam = movingForm
|
||||
biz.ErrIsNil(p.tagTreeApp.MovingTag(rc.MetaCtx, movingForm.FromPath, movingForm.ToPath))
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func (t *Team) ReqConfs() *req.Confs {
|
||||
}
|
||||
|
||||
func (p *Team) GetTeams(rc *req.Ctx) {
|
||||
queryCond := req.BindQuery(rc, new(entity.TeamQuery))
|
||||
queryCond := req.BindQuery[*entity.TeamQuery](rc)
|
||||
|
||||
res, err := p.teamApp.GetPageList(queryCond)
|
||||
biz.ErrIsNil(err)
|
||||
@@ -60,7 +60,7 @@ func (p *Team) GetTeams(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *Team) SaveTeam(rc *req.Ctx) {
|
||||
team := req.BindJsonAndValid(rc, new(dto.SaveTeam))
|
||||
team := req.BindJsonAndValid[*dto.SaveTeam](rc)
|
||||
rc.ReqParam = team
|
||||
biz.ErrIsNil(p.teamApp.SaveTeam(rc.MetaCtx, team))
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func (p *Team) GetTeamMembers(rc *req.Ctx) {
|
||||
|
||||
// 保存团队信息
|
||||
func (p *Team) SaveTeamMember(rc *req.Ctx) {
|
||||
teamMems := req.BindJsonAndValid(rc, new(form.TeamMember))
|
||||
teamMems := req.BindJsonAndValid[*form.TeamMember](rc)
|
||||
|
||||
teamId := teamMems.TeamId
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
)
|
||||
|
||||
type ResourceAuthCert struct {
|
||||
model.ExtraData
|
||||
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"` // 名称
|
||||
ResourceCode string `json:"resourceCode"` // 资源编号
|
||||
@@ -14,7 +16,6 @@ type ResourceAuthCert struct {
|
||||
Username string `json:"username"` // 用户名
|
||||
Ciphertext string `json:"ciphertext"` // 密文
|
||||
CiphertextType entity.AuthCertCiphertextType `json:"ciphertextType"` // 密文类型
|
||||
Extra model.Map[string, any] `json:"extra"` // 账号需要的其他额外信息(如秘钥口令等)
|
||||
Type entity.AuthCertType `json:"type"` // 凭证类型
|
||||
Remark string `json:"remark"` // 备注
|
||||
|
||||
|
||||
4
server/pkg/cache/cache.go
vendored
4
server/pkg/cache/cache.go
vendored
@@ -1,8 +1,8 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/jsonx"
|
||||
"time"
|
||||
|
||||
"github.com/may-fly/cast"
|
||||
@@ -65,7 +65,7 @@ func (dc *defaultCache) GetInt(k string) (int, bool) {
|
||||
|
||||
func (dc *defaultCache) GetJson(k string, valPtr any) bool {
|
||||
if val, ok := dc.GetStr(k); ok {
|
||||
jsonx.To(val, valPtr)
|
||||
json.Unmarshal([]byte(val), valPtr)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/structx"
|
||||
)
|
||||
|
||||
@@ -27,13 +26,8 @@ func PageResultConv[F any, T any](pageResult *PageResult[F]) *PageResult[T] {
|
||||
if pageResult == nil {
|
||||
return NewEmptyPageResult[T]()
|
||||
}
|
||||
|
||||
return &PageResult[T]{
|
||||
Total: pageResult.Total,
|
||||
List: collx.ArrayMap(pageResult.List, func(item F) T {
|
||||
t := structx.NewInstance[T]()
|
||||
structx.Copy(t, item)
|
||||
return t
|
||||
}),
|
||||
List: structx.CopySliceTo[F, T](pageResult.List),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ import (
|
||||
)
|
||||
|
||||
// 绑定并校验请求结构体参数
|
||||
func BindJsonAndValid[T any](rc *Ctx, data T) T {
|
||||
func BindJsonAndValid[T any](rc *Ctx) T {
|
||||
data := structx.NewInstance[T]()
|
||||
if err := rc.BindJSON(data); err != nil {
|
||||
panic(ConvBindValidationError(data, err))
|
||||
} else {
|
||||
@@ -18,15 +19,15 @@ func BindJsonAndValid[T any](rc *Ctx, data T) T {
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定请求体中的json至form结构体,并拷贝至另一结构体
|
||||
func BindJsonAndCopyTo[T any](rc *Ctx, form any, toStruct T) T {
|
||||
BindJsonAndValid(rc, form)
|
||||
structx.Copy(toStruct, form)
|
||||
return toStruct
|
||||
// 绑定请求体中的json至form结构体,并拷贝至指定结构体
|
||||
func BindJsonAndCopyTo[F, T any](rc *Ctx) (F, T) {
|
||||
f := BindJsonAndValid[F](rc)
|
||||
return f, structx.CopyTo[T](f)
|
||||
}
|
||||
|
||||
// 绑定查询字符串到指定结构体
|
||||
func BindQuery[T any](rc *Ctx, data T) T {
|
||||
func BindQuery[T any](rc *Ctx) T {
|
||||
data := structx.NewInstance[T]()
|
||||
if err := rc.BindQuery(data); err != nil {
|
||||
panic(ConvBindValidationError(data, err))
|
||||
} else {
|
||||
@@ -35,7 +36,8 @@ func BindQuery[T any](rc *Ctx, data T) T {
|
||||
}
|
||||
|
||||
// 绑定查询字符串到指定结构体,并将分页信息也返回
|
||||
func BindQueryAndPage[T any](rc *Ctx, data T) (T, model.PageParam) {
|
||||
func BindQueryAndPage[T any](rc *Ctx) (T, model.PageParam) {
|
||||
data := structx.NewInstance[T]()
|
||||
if err := rc.BindQuery(data); err != nil {
|
||||
panic(ConvBindValidationError(data, err))
|
||||
} else {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/structx"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
@@ -16,9 +17,10 @@ func ToMap(jsonStr string) (collx.M, error) {
|
||||
return ToMapByBytes([]byte(jsonStr))
|
||||
}
|
||||
|
||||
// json字符串转结构体
|
||||
func To[T any](jsonStr string, res T) (T, error) {
|
||||
return res, json.Unmarshal([]byte(jsonStr), &res)
|
||||
// json字符串转结构体, T需为指针类型
|
||||
func To[T any](jsonStr string) (T, error) {
|
||||
res := structx.NewInstance[T]()
|
||||
return res, json.Unmarshal([]byte(jsonStr), res)
|
||||
}
|
||||
|
||||
// json字节数组转map
|
||||
|
||||
874
server/pkg/utils/structx/copier.go
Normal file
874
server/pkg/utils/structx/copier.go
Normal file
@@ -0,0 +1,874 @@
|
||||
package structx
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// github.com/jinzhu/copier
|
||||
|
||||
var (
|
||||
ErrInvalidCopyDestination = errors.New("copy destination must be non-nil and addressable")
|
||||
ErrInvalidCopyFrom = errors.New("copy from must be non-nil and addressable")
|
||||
ErrMapKeyNotMatch = errors.New("map's key type doesn't match")
|
||||
ErrNotSupported = errors.New("not supported")
|
||||
ErrFieldNameTagStartNotUpperCase = errors.New("copier field name tag must be start upper case")
|
||||
)
|
||||
|
||||
// These flags define options for tag handling
|
||||
const (
|
||||
// Denotes that a destination field must be copied to. If copying fails then a panic will ensue.
|
||||
tagMust uint8 = 1 << iota
|
||||
|
||||
// Denotes that the program should not panic when the must flag is on and
|
||||
// value is not copied. The program will return an error instead.
|
||||
tagNoPanic
|
||||
|
||||
// Ignore a destination field from being copied to.
|
||||
tagIgnore
|
||||
|
||||
// Denotes the fact that the field should be overridden, no matter if the IgnoreEmpty is set
|
||||
tagOverride
|
||||
|
||||
// Denotes that the value as been copied
|
||||
hasCopied
|
||||
|
||||
// Some default converter types for a nicer syntax
|
||||
String string = ""
|
||||
Bool bool = false
|
||||
Int int = 0
|
||||
Float32 float32 = 0
|
||||
Float64 float64 = 0
|
||||
)
|
||||
|
||||
// Option sets copy options
|
||||
type Option struct {
|
||||
// setting this value to true will ignore copying zero values of all the fields, including bools, as well as a
|
||||
// struct having all it's fields set to their zero values respectively (see IsZero() in reflect/value.go)
|
||||
IgnoreEmpty bool
|
||||
CaseSensitive bool
|
||||
DeepCopy bool
|
||||
Converters []TypeConverter
|
||||
// Custom field name mappings to copy values with different names in `fromValue` and `toValue` types.
|
||||
// Examples can be found in `copier_field_name_mapping_test.go`.
|
||||
FieldNameMapping []FieldNameMapping
|
||||
}
|
||||
|
||||
func (opt Option) converters() map[converterPair]TypeConverter {
|
||||
var converters = map[converterPair]TypeConverter{}
|
||||
|
||||
// save converters into map for faster lookup
|
||||
for i := range opt.Converters {
|
||||
pair := converterPair{
|
||||
SrcType: reflect.TypeOf(opt.Converters[i].SrcType),
|
||||
DstType: reflect.TypeOf(opt.Converters[i].DstType),
|
||||
}
|
||||
|
||||
converters[pair] = opt.Converters[i]
|
||||
}
|
||||
|
||||
return converters
|
||||
}
|
||||
|
||||
type TypeConverter struct {
|
||||
SrcType interface{}
|
||||
DstType interface{}
|
||||
Fn func(src interface{}) (dst interface{}, err error)
|
||||
}
|
||||
|
||||
type converterPair struct {
|
||||
SrcType reflect.Type
|
||||
DstType reflect.Type
|
||||
}
|
||||
|
||||
func (opt Option) fieldNameMapping() map[converterPair]FieldNameMapping {
|
||||
var mapping = map[converterPair]FieldNameMapping{}
|
||||
|
||||
for i := range opt.FieldNameMapping {
|
||||
pair := converterPair{
|
||||
SrcType: reflect.TypeOf(opt.FieldNameMapping[i].SrcType),
|
||||
DstType: reflect.TypeOf(opt.FieldNameMapping[i].DstType),
|
||||
}
|
||||
|
||||
mapping[pair] = opt.FieldNameMapping[i]
|
||||
}
|
||||
|
||||
return mapping
|
||||
}
|
||||
|
||||
type FieldNameMapping struct {
|
||||
SrcType interface{}
|
||||
DstType interface{}
|
||||
Mapping map[string]string
|
||||
}
|
||||
|
||||
// Tag Flags
|
||||
type flags struct {
|
||||
BitFlags map[string]uint8
|
||||
SrcNames tagNameMapping
|
||||
DestNames tagNameMapping
|
||||
}
|
||||
|
||||
// Field Tag name mapping
|
||||
type tagNameMapping struct {
|
||||
FieldNameToTag map[string]string
|
||||
TagToFieldName map[string]string
|
||||
}
|
||||
|
||||
// Copy copy things
|
||||
func Copy(toValue interface{}, fromValue interface{}) (err error) {
|
||||
return copier(toValue, fromValue, Option{})
|
||||
}
|
||||
|
||||
// CopyWithOption copy with option
|
||||
func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error) {
|
||||
return copier(toValue, fromValue, opt)
|
||||
}
|
||||
|
||||
func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) {
|
||||
var (
|
||||
isSlice bool
|
||||
amount = 1
|
||||
from = indirect(reflect.ValueOf(fromValue))
|
||||
to = indirect(reflect.ValueOf(toValue))
|
||||
converters = opt.converters()
|
||||
mappings = opt.fieldNameMapping()
|
||||
)
|
||||
|
||||
if !to.CanAddr() {
|
||||
return ErrInvalidCopyDestination
|
||||
}
|
||||
|
||||
// Return is from value is invalid
|
||||
if !from.IsValid() {
|
||||
return ErrInvalidCopyFrom
|
||||
}
|
||||
|
||||
fromType, isPtrFrom := indirectType(from.Type())
|
||||
toType, _ := indirectType(to.Type())
|
||||
|
||||
if fromType.Kind() == reflect.Interface {
|
||||
fromType = reflect.TypeOf(from.Interface())
|
||||
}
|
||||
|
||||
if toType.Kind() == reflect.Interface {
|
||||
toType, _ = indirectType(reflect.TypeOf(to.Interface()))
|
||||
oldTo := to
|
||||
to = reflect.New(reflect.TypeOf(to.Interface())).Elem()
|
||||
defer func() {
|
||||
oldTo.Set(to)
|
||||
}()
|
||||
}
|
||||
|
||||
// Just set it if possible to assign for normal types
|
||||
if from.Kind() != reflect.Slice && from.Kind() != reflect.Struct && from.Kind() != reflect.Map && (from.Type().AssignableTo(to.Type()) || from.Type().ConvertibleTo(to.Type())) {
|
||||
if !isPtrFrom || !opt.DeepCopy {
|
||||
to.Set(from.Convert(to.Type()))
|
||||
} else {
|
||||
fromCopy := reflect.New(from.Type())
|
||||
fromCopy.Set(from.Elem())
|
||||
to.Set(fromCopy.Convert(to.Type()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if from.Kind() != reflect.Slice && fromType.Kind() == reflect.Map && toType.Kind() == reflect.Map {
|
||||
if !fromType.Key().ConvertibleTo(toType.Key()) {
|
||||
return ErrMapKeyNotMatch
|
||||
}
|
||||
|
||||
if to.IsNil() {
|
||||
to.Set(reflect.MakeMapWithSize(toType, from.Len()))
|
||||
}
|
||||
|
||||
for _, k := range from.MapKeys() {
|
||||
toKey := indirect(reflect.New(toType.Key()))
|
||||
isSet, err := set(toKey, k, opt.DeepCopy, converters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isSet {
|
||||
return fmt.Errorf("%w map, old key: %v, new key: %v", ErrNotSupported, k.Type(), toType.Key())
|
||||
}
|
||||
|
||||
elemType := toType.Elem()
|
||||
if elemType.Kind() != reflect.Slice {
|
||||
elemType, _ = indirectType(elemType)
|
||||
}
|
||||
toValue := indirect(reflect.New(elemType))
|
||||
isSet, err = set(toValue, from.MapIndex(k), opt.DeepCopy, converters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isSet {
|
||||
if err = copier(toValue.Addr().Interface(), from.MapIndex(k).Interface(), opt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
if elemType == toType.Elem() {
|
||||
to.SetMapIndex(toKey, toValue)
|
||||
break
|
||||
}
|
||||
elemType = reflect.PointerTo(elemType)
|
||||
toValue = toValue.Addr()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if from.Kind() == reflect.Slice && to.Kind() == reflect.Slice {
|
||||
// Return directly if both slices are nil
|
||||
if from.IsNil() && to.IsNil() {
|
||||
return
|
||||
}
|
||||
if to.IsNil() {
|
||||
slice := reflect.MakeSlice(reflect.SliceOf(to.Type().Elem()), from.Len(), from.Cap())
|
||||
to.Set(slice)
|
||||
}
|
||||
if fromType.ConvertibleTo(toType) {
|
||||
for i := 0; i < from.Len(); i++ {
|
||||
if to.Len() < i+1 {
|
||||
to.Set(reflect.Append(to, reflect.New(to.Type().Elem()).Elem()))
|
||||
}
|
||||
isSet, err := set(to.Index(i), from.Index(i), opt.DeepCopy, converters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isSet {
|
||||
// ignore error while copy slice element
|
||||
err = copier(to.Index(i).Addr().Interface(), from.Index(i).Interface(), opt)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if to.Len() > from.Len() {
|
||||
to.SetLen(from.Len())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if fromType.Kind() != reflect.Struct || toType.Kind() != reflect.Struct {
|
||||
// skip not supported type
|
||||
return
|
||||
}
|
||||
|
||||
if len(converters) > 0 {
|
||||
if ok, e := set(to, from, opt.DeepCopy, converters); e == nil && ok {
|
||||
// converter supported
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if from.Kind() == reflect.Slice || to.Kind() == reflect.Slice {
|
||||
isSlice = true
|
||||
if from.Kind() == reflect.Slice {
|
||||
amount = from.Len()
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < amount; i++ {
|
||||
var dest, source reflect.Value
|
||||
|
||||
if isSlice {
|
||||
// source
|
||||
if from.Kind() == reflect.Slice {
|
||||
source = indirect(from.Index(i))
|
||||
} else {
|
||||
source = indirect(from)
|
||||
}
|
||||
// dest
|
||||
dest = indirect(reflect.New(toType).Elem())
|
||||
} else {
|
||||
source = indirect(from)
|
||||
dest = indirect(to)
|
||||
}
|
||||
|
||||
if len(converters) > 0 {
|
||||
if ok, e := set(dest, source, opt.DeepCopy, converters); e == nil && ok {
|
||||
if isSlice {
|
||||
// FIXME: maybe should check the other types?
|
||||
if to.Type().Elem().Kind() == reflect.Ptr {
|
||||
to.Index(i).Set(dest.Addr())
|
||||
} else {
|
||||
if to.Len() < i+1 {
|
||||
reflect.Append(to, dest)
|
||||
} else {
|
||||
to.Index(i).Set(dest)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
to.Set(dest)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
destKind := dest.Kind()
|
||||
initDest := false
|
||||
if destKind == reflect.Interface {
|
||||
initDest = true
|
||||
dest = indirect(reflect.New(toType))
|
||||
}
|
||||
|
||||
// Get tag options
|
||||
flgs, err := getFlags(dest, source, toType, fromType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check source
|
||||
if source.IsValid() {
|
||||
copyUnexportedStructFields(dest, source)
|
||||
|
||||
// Copy from source field to dest field or method
|
||||
fromTypeFields := deepFields(fromType)
|
||||
for _, field := range fromTypeFields {
|
||||
name := field.Name
|
||||
|
||||
// Get bit flags for field
|
||||
fieldFlags := flgs.BitFlags[name]
|
||||
|
||||
// Check if we should ignore copying
|
||||
if (fieldFlags & tagIgnore) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldNamesMapping := getFieldNamesMapping(mappings, fromType, toType)
|
||||
|
||||
srcFieldName, destFieldName := getFieldName(name, flgs, fieldNamesMapping)
|
||||
|
||||
if fromField := fieldByNameOrZeroValue(source, srcFieldName); fromField.IsValid() && !shouldIgnore(fromField, fieldFlags, opt.IgnoreEmpty) {
|
||||
// process for nested anonymous field
|
||||
destFieldNotSet := false
|
||||
if f, ok := dest.Type().FieldByName(destFieldName); ok {
|
||||
// only initialize parent embedded struct pointer in the path
|
||||
for idx := range f.Index[:len(f.Index)-1] {
|
||||
destField := dest.FieldByIndex(f.Index[:idx+1])
|
||||
|
||||
if destField.Kind() != reflect.Ptr {
|
||||
continue
|
||||
}
|
||||
|
||||
if !destField.IsNil() {
|
||||
continue
|
||||
}
|
||||
if !destField.CanSet() {
|
||||
destFieldNotSet = true
|
||||
break
|
||||
}
|
||||
|
||||
// destField is a nil pointer that can be set
|
||||
newValue := reflect.New(destField.Type().Elem())
|
||||
destField.Set(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
if destFieldNotSet {
|
||||
break
|
||||
}
|
||||
|
||||
toField := fieldByName(dest, destFieldName, opt.CaseSensitive)
|
||||
if toField.IsValid() {
|
||||
if toField.CanSet() {
|
||||
isSet, err := set(toField, fromField, opt.DeepCopy, converters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isSet {
|
||||
if err := copier(toField.Addr().Interface(), fromField.Interface(), opt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if fieldFlags != 0 {
|
||||
// Note that a copy was made
|
||||
flgs.BitFlags[name] = fieldFlags | hasCopied
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// try to set to method
|
||||
var toMethod reflect.Value
|
||||
if dest.CanAddr() {
|
||||
toMethod = dest.Addr().MethodByName(destFieldName)
|
||||
} else {
|
||||
toMethod = dest.MethodByName(destFieldName)
|
||||
}
|
||||
|
||||
if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
|
||||
toMethod.Call([]reflect.Value{fromField})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy from from method to dest field
|
||||
for _, field := range deepFields(toType) {
|
||||
name := field.Name
|
||||
srcFieldName, destFieldName := getFieldName(name, flgs, getFieldNamesMapping(mappings, fromType, toType))
|
||||
|
||||
var fromMethod reflect.Value
|
||||
if source.CanAddr() {
|
||||
fromMethod = source.Addr().MethodByName(srcFieldName)
|
||||
} else {
|
||||
fromMethod = source.MethodByName(srcFieldName)
|
||||
}
|
||||
|
||||
if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 && !shouldIgnore(fromMethod, flgs.BitFlags[name], opt.IgnoreEmpty) {
|
||||
if toField := fieldByName(dest, destFieldName, opt.CaseSensitive); toField.IsValid() && toField.CanSet() {
|
||||
values := fromMethod.Call([]reflect.Value{})
|
||||
if len(values) >= 1 {
|
||||
set(toField, values[0], opt.DeepCopy, converters)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isSlice && to.Kind() == reflect.Slice {
|
||||
if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
|
||||
if to.Len() < i+1 {
|
||||
to.Set(reflect.Append(to, dest.Addr()))
|
||||
} else {
|
||||
isSet, err := set(to.Index(i), dest.Addr(), opt.DeepCopy, converters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isSet {
|
||||
// ignore error while copy slice element
|
||||
err = copier(to.Index(i).Addr().Interface(), dest.Addr().Interface(), opt)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if dest.Type().AssignableTo(to.Type().Elem()) {
|
||||
if to.Len() < i+1 {
|
||||
to.Set(reflect.Append(to, dest))
|
||||
} else {
|
||||
isSet, err := set(to.Index(i), dest, opt.DeepCopy, converters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isSet {
|
||||
// ignore error while copy slice element
|
||||
err = copier(to.Index(i).Addr().Interface(), dest.Interface(), opt)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if initDest {
|
||||
to.Set(dest)
|
||||
}
|
||||
|
||||
err = checkBitFlags(flgs.BitFlags)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getFieldNamesMapping(mappings map[converterPair]FieldNameMapping, fromType reflect.Type, toType reflect.Type) map[string]string {
|
||||
var fieldNamesMapping map[string]string
|
||||
|
||||
if len(mappings) > 0 {
|
||||
pair := converterPair{
|
||||
SrcType: fromType,
|
||||
DstType: toType,
|
||||
}
|
||||
if v, ok := mappings[pair]; ok {
|
||||
fieldNamesMapping = v.Mapping
|
||||
}
|
||||
}
|
||||
return fieldNamesMapping
|
||||
}
|
||||
|
||||
func fieldByNameOrZeroValue(source reflect.Value, fieldName string) (value reflect.Value) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
value = reflect.Value{}
|
||||
}
|
||||
}()
|
||||
|
||||
return source.FieldByName(fieldName)
|
||||
}
|
||||
|
||||
func copyUnexportedStructFields(to, from reflect.Value) {
|
||||
if from.Kind() != reflect.Struct || to.Kind() != reflect.Struct || !from.Type().AssignableTo(to.Type()) {
|
||||
return
|
||||
}
|
||||
|
||||
// create a shallow copy of 'to' to get all fields
|
||||
tmp := indirect(reflect.New(to.Type()))
|
||||
tmp.Set(from)
|
||||
|
||||
// revert exported fields
|
||||
for i := 0; i < to.NumField(); i++ {
|
||||
if tmp.Field(i).CanSet() {
|
||||
tmp.Field(i).Set(to.Field(i))
|
||||
}
|
||||
}
|
||||
to.Set(tmp)
|
||||
}
|
||||
|
||||
func shouldIgnore(v reflect.Value, bitFlags uint8, ignoreEmpty bool) bool {
|
||||
return ignoreEmpty && bitFlags&tagOverride == 0 && v.IsZero()
|
||||
}
|
||||
|
||||
var deepFieldsLock sync.RWMutex
|
||||
var deepFieldsMap = make(map[reflect.Type][]reflect.StructField)
|
||||
|
||||
func deepFields(reflectType reflect.Type) []reflect.StructField {
|
||||
deepFieldsLock.RLock()
|
||||
cache, ok := deepFieldsMap[reflectType]
|
||||
deepFieldsLock.RUnlock()
|
||||
if ok {
|
||||
return cache
|
||||
}
|
||||
var res []reflect.StructField
|
||||
if reflectType, _ = indirectType(reflectType); reflectType.Kind() == reflect.Struct {
|
||||
fields := make([]reflect.StructField, 0, reflectType.NumField())
|
||||
|
||||
for i := 0; i < reflectType.NumField(); i++ {
|
||||
v := reflectType.Field(i)
|
||||
// PkgPath is the package path that qualifies a lower case (unexported)
|
||||
// field name. It is empty for upper case (exported) field names.
|
||||
// See https://golang.org/ref/spec#Uniqueness_of_identifiers
|
||||
if v.PkgPath == "" {
|
||||
fields = append(fields, v)
|
||||
if v.Anonymous {
|
||||
// also consider fields of anonymous fields as fields of the root
|
||||
fields = append(fields, deepFields(v.Type)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
res = fields
|
||||
}
|
||||
|
||||
deepFieldsLock.Lock()
|
||||
deepFieldsMap[reflectType] = res
|
||||
deepFieldsLock.Unlock()
|
||||
return res
|
||||
}
|
||||
|
||||
func indirect(reflectValue reflect.Value) reflect.Value {
|
||||
for reflectValue.Kind() == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
}
|
||||
return reflectValue
|
||||
}
|
||||
|
||||
func indirectType(reflectType reflect.Type) (_ reflect.Type, isPtr bool) {
|
||||
for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
|
||||
reflectType = reflectType.Elem()
|
||||
isPtr = true
|
||||
}
|
||||
return reflectType, isPtr
|
||||
}
|
||||
|
||||
func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]TypeConverter) (bool, error) {
|
||||
if !from.IsValid() {
|
||||
return true, nil
|
||||
}
|
||||
if ok, err := lookupAndCopyWithConverter(to, from, converters); err != nil {
|
||||
return false, err
|
||||
} else if ok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if to.Kind() == reflect.Ptr {
|
||||
// set `to` to nil if from is nil
|
||||
if from.Kind() == reflect.Ptr && from.IsNil() {
|
||||
to.Set(reflect.Zero(to.Type()))
|
||||
return true, nil
|
||||
} else if to.IsNil() {
|
||||
// `from` -> `to`
|
||||
// sql.NullString -> *string
|
||||
if fromValuer, ok := driverValuer(from); ok {
|
||||
v, err := fromValuer.Value()
|
||||
if err != nil {
|
||||
return true, nil
|
||||
}
|
||||
// if `from` is not valid do nothing with `to`
|
||||
if v == nil {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
// allocate new `to` variable with default value (eg. *string -> new(string))
|
||||
to.Set(reflect.New(to.Type().Elem()))
|
||||
} else if from.Kind() != reflect.Ptr && from.IsZero() {
|
||||
to.Set(reflect.Zero(to.Type()))
|
||||
return true, nil
|
||||
}
|
||||
// depointer `to`
|
||||
to = to.Elem()
|
||||
}
|
||||
|
||||
if deepCopy {
|
||||
toKind := to.Kind()
|
||||
if toKind == reflect.Interface && to.IsNil() {
|
||||
if reflect.TypeOf(from.Interface()) != nil {
|
||||
to.Set(reflect.New(reflect.TypeOf(from.Interface())).Elem())
|
||||
toKind = reflect.TypeOf(to.Interface()).Kind()
|
||||
}
|
||||
}
|
||||
if from.Kind() == reflect.Ptr && from.IsNil() {
|
||||
to.Set(reflect.Zero(to.Type()))
|
||||
return true, nil
|
||||
}
|
||||
if _, ok := to.Addr().Interface().(sql.Scanner); !ok && (toKind == reflect.Struct || toKind == reflect.Map || toKind == reflect.Slice) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// try convert directly
|
||||
if from.Type().ConvertibleTo(to.Type()) {
|
||||
to.Set(from.Convert(to.Type()))
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// try Scanner
|
||||
if toScanner, ok := to.Addr().Interface().(sql.Scanner); ok {
|
||||
// `from` -> `to`
|
||||
// *string -> sql.NullString
|
||||
if from.Kind() == reflect.Ptr {
|
||||
// if `from` is nil do nothing with `to`
|
||||
if from.IsNil() {
|
||||
return true, nil
|
||||
}
|
||||
// depointer `from`
|
||||
from = indirect(from)
|
||||
}
|
||||
// `from` -> `to`
|
||||
// string -> sql.NullString
|
||||
// set `to` by invoking method Scan(`from`)
|
||||
err := toScanner.Scan(from.Interface())
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// try Valuer
|
||||
if fromValuer, ok := driverValuer(from); ok {
|
||||
// `from` -> `to`
|
||||
// sql.NullString -> string
|
||||
v, err := fromValuer.Value()
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
// if `from` is not valid do nothing with `to`
|
||||
if v == nil {
|
||||
return true, nil
|
||||
}
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Type().AssignableTo(to.Type()) {
|
||||
to.Set(rv)
|
||||
return true, nil
|
||||
}
|
||||
if to.CanSet() && rv.Type().ConvertibleTo(to.Type()) {
|
||||
to.Set(rv.Convert(to.Type()))
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// from is ptr
|
||||
if from.Kind() == reflect.Ptr {
|
||||
return set(to, from.Elem(), deepCopy, converters)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// lookupAndCopyWithConverter looks up the type pair, on success the TypeConverter Fn func is called to copy src to dst field.
|
||||
func lookupAndCopyWithConverter(to, from reflect.Value, converters map[converterPair]TypeConverter) (copied bool, err error) {
|
||||
pair := converterPair{
|
||||
SrcType: from.Type(),
|
||||
DstType: to.Type(),
|
||||
}
|
||||
|
||||
if cnv, ok := converters[pair]; ok {
|
||||
result, err := cnv.Fn(from.Interface())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
to.Set(reflect.ValueOf(result))
|
||||
} else {
|
||||
// in case we've got a nil value to copy
|
||||
to.Set(reflect.Zero(to.Type()))
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// parseTags Parses struct tags and returns uint8 bit flags.
|
||||
func parseTags(tag string) (flg uint8, name string, err error) {
|
||||
for _, t := range strings.Split(tag, ",") {
|
||||
switch t {
|
||||
case "-":
|
||||
flg = tagIgnore
|
||||
return
|
||||
case "must":
|
||||
flg = flg | tagMust
|
||||
case "nopanic":
|
||||
flg = flg | tagNoPanic
|
||||
case "override":
|
||||
flg = flg | tagOverride
|
||||
default:
|
||||
if unicode.IsUpper([]rune(t)[0]) {
|
||||
name = strings.TrimSpace(t)
|
||||
} else {
|
||||
err = ErrFieldNameTagStartNotUpperCase
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getTagFlags Parses struct tags for bit flags, field name.
|
||||
func getFlags(dest, src reflect.Value, toType, fromType reflect.Type) (flags, error) {
|
||||
flgs := flags{
|
||||
BitFlags: map[string]uint8{},
|
||||
SrcNames: tagNameMapping{
|
||||
FieldNameToTag: map[string]string{},
|
||||
TagToFieldName: map[string]string{},
|
||||
},
|
||||
DestNames: tagNameMapping{
|
||||
FieldNameToTag: map[string]string{},
|
||||
TagToFieldName: map[string]string{},
|
||||
},
|
||||
}
|
||||
|
||||
var toTypeFields, fromTypeFields []reflect.StructField
|
||||
if dest.IsValid() {
|
||||
toTypeFields = deepFields(toType)
|
||||
}
|
||||
if src.IsValid() {
|
||||
fromTypeFields = deepFields(fromType)
|
||||
}
|
||||
|
||||
// Get a list dest of tags
|
||||
for _, field := range toTypeFields {
|
||||
tags := field.Tag.Get("copier")
|
||||
if tags != "" {
|
||||
var name string
|
||||
var err error
|
||||
if flgs.BitFlags[field.Name], name, err = parseTags(tags); err != nil {
|
||||
return flags{}, err
|
||||
} else if name != "" {
|
||||
flgs.DestNames.FieldNameToTag[field.Name] = name
|
||||
flgs.DestNames.TagToFieldName[name] = field.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list source of tags
|
||||
for _, field := range fromTypeFields {
|
||||
tags := field.Tag.Get("copier")
|
||||
if tags != "" {
|
||||
var name string
|
||||
var err error
|
||||
|
||||
if _, name, err = parseTags(tags); err != nil {
|
||||
return flags{}, err
|
||||
} else if name != "" {
|
||||
flgs.SrcNames.FieldNameToTag[field.Name] = name
|
||||
flgs.SrcNames.TagToFieldName[name] = field.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return flgs, nil
|
||||
}
|
||||
|
||||
// checkBitFlags Checks flags for error or panic conditions.
|
||||
func checkBitFlags(flagsList map[string]uint8) (err error) {
|
||||
// Check flag conditions were met
|
||||
for name, flgs := range flagsList {
|
||||
if flgs&hasCopied == 0 {
|
||||
switch {
|
||||
case flgs&tagMust != 0 && flgs&tagNoPanic != 0:
|
||||
err = fmt.Errorf("field %s has must tag but was not copied", name)
|
||||
return
|
||||
case flgs&(tagMust) != 0:
|
||||
panic(fmt.Sprintf("Field %s has must tag but was not copied", name))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getFieldName(fieldName string, flgs flags, fieldNameMapping map[string]string) (srcFieldName string, destFieldName string) {
|
||||
// get dest field name
|
||||
if name, ok := fieldNameMapping[fieldName]; ok {
|
||||
srcFieldName = fieldName
|
||||
destFieldName = name
|
||||
return
|
||||
}
|
||||
|
||||
if srcTagName, ok := flgs.SrcNames.FieldNameToTag[fieldName]; ok {
|
||||
destFieldName = srcTagName
|
||||
if destTagName, ok := flgs.DestNames.TagToFieldName[srcTagName]; ok {
|
||||
destFieldName = destTagName
|
||||
}
|
||||
} else {
|
||||
if destTagName, ok := flgs.DestNames.TagToFieldName[fieldName]; ok {
|
||||
destFieldName = destTagName
|
||||
}
|
||||
}
|
||||
if destFieldName == "" {
|
||||
destFieldName = fieldName
|
||||
}
|
||||
|
||||
// get source field name
|
||||
if destTagName, ok := flgs.DestNames.FieldNameToTag[fieldName]; ok {
|
||||
srcFieldName = destTagName
|
||||
if srcField, ok := flgs.SrcNames.TagToFieldName[destTagName]; ok {
|
||||
srcFieldName = srcField
|
||||
}
|
||||
} else {
|
||||
if srcField, ok := flgs.SrcNames.TagToFieldName[fieldName]; ok {
|
||||
srcFieldName = srcField
|
||||
}
|
||||
}
|
||||
|
||||
if srcFieldName == "" {
|
||||
srcFieldName = fieldName
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func driverValuer(v reflect.Value) (i driver.Valuer, ok bool) {
|
||||
if !v.CanAddr() {
|
||||
i, ok = v.Interface().(driver.Valuer)
|
||||
return
|
||||
}
|
||||
|
||||
i, ok = v.Addr().Interface().(driver.Valuer)
|
||||
return
|
||||
}
|
||||
|
||||
func fieldByName(v reflect.Value, name string, caseSensitive bool) reflect.Value {
|
||||
if caseSensitive {
|
||||
return v.FieldByName(name)
|
||||
}
|
||||
|
||||
return v.FieldByNameFunc(func(n string) bool { return strings.EqualFold(n, name) })
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package structx
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -11,126 +10,18 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Copy copy things,引用至copier
|
||||
func Copy(toValue any, fromValue any) (err error) {
|
||||
var (
|
||||
isSlice bool
|
||||
amount = 1
|
||||
from = Indirect(reflect.ValueOf(fromValue))
|
||||
to = Indirect(reflect.ValueOf(toValue))
|
||||
)
|
||||
// CopyTo 将fromValue转为T类型并返回
|
||||
func CopyTo[T any](fromValue any) T {
|
||||
t := NewInstance[T]()
|
||||
Copy(t, fromValue)
|
||||
return t
|
||||
}
|
||||
|
||||
if !to.CanAddr() {
|
||||
return errors.New("copy to value is unaddressable")
|
||||
}
|
||||
|
||||
// Return is from value is invalid
|
||||
if !from.IsValid() {
|
||||
return
|
||||
}
|
||||
|
||||
fromType := IndirectType(from.Type())
|
||||
toType := IndirectType(to.Type())
|
||||
|
||||
// Just set it if possible to assign
|
||||
// And need to do copy anyway if the type is struct
|
||||
if fromType.Kind() != reflect.Struct && from.Type().AssignableTo(to.Type()) {
|
||||
to.Set(from)
|
||||
return
|
||||
}
|
||||
|
||||
if fromType.Kind() != reflect.Struct || toType.Kind() != reflect.Struct {
|
||||
return
|
||||
}
|
||||
|
||||
if to.Kind() == reflect.Slice {
|
||||
isSlice = true
|
||||
if from.Kind() == reflect.Slice {
|
||||
amount = from.Len()
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < amount; i++ {
|
||||
var dest, source reflect.Value
|
||||
|
||||
if isSlice {
|
||||
// source
|
||||
if from.Kind() == reflect.Slice {
|
||||
source = Indirect(from.Index(i))
|
||||
} else {
|
||||
source = Indirect(from)
|
||||
}
|
||||
// dest
|
||||
dest = Indirect(reflect.New(toType).Elem())
|
||||
} else {
|
||||
source = Indirect(from)
|
||||
dest = Indirect(to)
|
||||
}
|
||||
|
||||
// check source
|
||||
if source.IsValid() {
|
||||
fromTypeFields := deepFields(fromType)
|
||||
//fmt.Printf("%#v", fromTypeFields)
|
||||
// Copy from field to field or method
|
||||
for _, field := range fromTypeFields {
|
||||
name := field.Name
|
||||
|
||||
if fromField := source.FieldByName(name); fromField.IsValid() {
|
||||
// has field
|
||||
if toField := dest.FieldByName(name); toField.IsValid() {
|
||||
if toField.CanSet() {
|
||||
if !set(toField, fromField) {
|
||||
if err := Copy(toField.Addr().Interface(), fromField.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// try to set to method
|
||||
var toMethod reflect.Value
|
||||
if dest.CanAddr() {
|
||||
toMethod = dest.Addr().MethodByName(name)
|
||||
} else {
|
||||
toMethod = dest.MethodByName(name)
|
||||
}
|
||||
|
||||
if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
|
||||
toMethod.Call([]reflect.Value{fromField})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy from method to field
|
||||
for _, field := range deepFields(toType) {
|
||||
name := field.Name
|
||||
|
||||
var fromMethod reflect.Value
|
||||
if source.CanAddr() {
|
||||
fromMethod = source.Addr().MethodByName(name)
|
||||
} else {
|
||||
fromMethod = source.MethodByName(name)
|
||||
}
|
||||
|
||||
if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 {
|
||||
if toField := dest.FieldByName(name); toField.IsValid() && toField.CanSet() {
|
||||
values := fromMethod.Call([]reflect.Value{})
|
||||
if len(values) >= 1 {
|
||||
set(toField, values[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if isSlice {
|
||||
if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
|
||||
to.Set(reflect.Append(to, dest.Addr()))
|
||||
} else if dest.Type().AssignableTo(to.Type().Elem()) {
|
||||
to.Set(reflect.Append(to, dest))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
// CopySliceTo 将fromValue转为[]T类型并返回
|
||||
func CopySliceTo[F, T any](fromValue []F) []T {
|
||||
var to []T
|
||||
Copy(&to, fromValue)
|
||||
return to
|
||||
}
|
||||
|
||||
// 对结构体的每个字段以及字段值执行doWith回调函数, 包括匿名属性的字段
|
||||
@@ -158,23 +49,6 @@ func DoWithFields(str any, doWith func(fType reflect.StructField, fValue reflect
|
||||
return nil
|
||||
}
|
||||
|
||||
func deepFields(reflectType reflect.Type) []reflect.StructField {
|
||||
var fields []reflect.StructField
|
||||
|
||||
if reflectType = IndirectType(reflectType); reflectType.Kind() == reflect.Struct {
|
||||
for i := 0; i < reflectType.NumField(); i++ {
|
||||
v := reflectType.Field(i)
|
||||
if v.Anonymous {
|
||||
fields = append(fields, deepFields(v.Type)...)
|
||||
} else {
|
||||
fields = append(fields, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
func Indirect(reflectValue reflect.Value) reflect.Value {
|
||||
for reflectValue.Kind() == reflect.Ptr {
|
||||
reflectValue = reflectValue.Elem()
|
||||
@@ -189,35 +63,6 @@ func IndirectType(reflectType reflect.Type) reflect.Type {
|
||||
return reflectType
|
||||
}
|
||||
|
||||
func set(to, from reflect.Value) bool {
|
||||
if from.IsValid() {
|
||||
if to.Kind() == reflect.Ptr {
|
||||
//set `to` to nil if from is nil
|
||||
if from.Kind() == reflect.Ptr && from.IsNil() {
|
||||
to.Set(reflect.Zero(to.Type()))
|
||||
return true
|
||||
} else if to.IsNil() {
|
||||
to.Set(reflect.New(to.Type().Elem()))
|
||||
}
|
||||
to = to.Elem()
|
||||
}
|
||||
|
||||
if from.Type().ConvertibleTo(to.Type()) {
|
||||
to.Set(from.Convert(to.Type()))
|
||||
} else if scanner, ok := to.Addr().Interface().(sql.Scanner); ok {
|
||||
err := scanner.Scan(from.Interface())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
} else if from.Kind() == reflect.Ptr {
|
||||
return set(to, from.Elem())
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func Map2Struct(m map[string]any, s any) error {
|
||||
toValue := Indirect(reflect.ValueOf(s))
|
||||
if !toValue.CanAddr() {
|
||||
|
||||
Reference in New Issue
Block a user