optimize code of component attrbute update api
This commit is contained in:
parent
f47e278f85
commit
60eab0675e
|
|
@ -4,9 +4,10 @@ package database
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"modelRT/orm"
|
||||
"time"
|
||||
|
||||
"modelRT/orm"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
|
@ -54,6 +55,23 @@ func QueryComponentByUUID(ctx context.Context, tx *gorm.DB, uuid uuid.UUID) (orm
|
|||
return component, nil
|
||||
}
|
||||
|
||||
// QueryComponentByCompTag return the result of query circuit diagram component info by component tag from postgresDB
|
||||
func QueryComponentByCompTag(ctx context.Context, tx *gorm.DB, tag string) (orm.Component, error) {
|
||||
var component orm.Component
|
||||
// ctx超时判断
|
||||
cancelCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
result := tx.WithContext(cancelCtx).
|
||||
Where("tag = ?", tag).
|
||||
Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||
First(&component)
|
||||
|
||||
if result.Error != nil {
|
||||
return orm.Component{}, result.Error
|
||||
}
|
||||
return component, nil
|
||||
}
|
||||
|
||||
// QueryComponentByPageID return the result of query circuit diagram component info by page id from postgresDB
|
||||
func QueryComponentByPageID(ctx context.Context, tx *gorm.DB, uuid uuid.UUID) (orm.Component, error) {
|
||||
var component orm.Component
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package database
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"modelRT/logger"
|
||||
|
|
@ -27,3 +29,50 @@ func QueryArrtibuteRecordByUUID(ctx context.Context, tx *gorm.DB, gridID, zoneID
|
|||
}
|
||||
return pages, nil
|
||||
}
|
||||
|
||||
// GetProjectNameByTagAndGroupName 根据 tag 和 meta_model 获取项目名称
|
||||
func GetProjectNameByTagAndGroupName(db *gorm.DB, tag string, groupName string) (string, error) {
|
||||
var project orm.ProjectManager
|
||||
|
||||
// 使用 Select 只提取 name 字段,提高查询效率
|
||||
// 使用 Where 进行多列条件过滤
|
||||
err := db.Select("name").
|
||||
Where("tag = ? AND meta_model = ?", tag, groupName).
|
||||
First(&project).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return "", fmt.Errorf("project not found with tag: %s and model: %s", tag, groupName)
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
return project.Name, nil
|
||||
}
|
||||
|
||||
// BatchGetProjectNames define func to batch retrieve name based on multiple tags and metaModel
|
||||
func BatchGetProjectNames(db *gorm.DB, identifiers []orm.ProjectIdentifier) (map[orm.ProjectIdentifier]string, error) {
|
||||
if len(identifiers) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var projects []orm.ProjectManager
|
||||
queryArgs := make([][]any, len(identifiers))
|
||||
for i, id := range identifiers {
|
||||
queryArgs[i] = []any{id.Tag, id.MetaModel}
|
||||
}
|
||||
|
||||
err := db.Select("tag", "meta_model", "name").
|
||||
Where("(tag, meta_model) IN ?", queryArgs).
|
||||
Find(&projects).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultMap := make(map[orm.ProjectIdentifier]string)
|
||||
for _, p := range projects {
|
||||
key := orm.ProjectIdentifier{Tag: p.Tag, MetaModel: p.MetaModel}
|
||||
resultMap[key] = p.Name
|
||||
}
|
||||
|
||||
return resultMap, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,20 @@ package handler
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"modelRT/database"
|
||||
"modelRT/diagram"
|
||||
"modelRT/logger"
|
||||
"modelRT/network"
|
||||
"modelRT/orm"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gofrs/uuid"
|
||||
)
|
||||
|
||||
// ComponentAttributeUpdateHandler define circuit diagram component attribute value update process API
|
||||
func ComponentAttributeUpdateHandler(c *gin.Context) {
|
||||
pgClient := database.GetPostgresDBClient()
|
||||
|
||||
var request network.ComponentAttributeUpdateInfo
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
logger.Error(c, "unmarshal circuit diagram component attribute update info failed", "error", err)
|
||||
|
|
@ -30,28 +30,57 @@ func ComponentAttributeUpdateHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
componentUUID := uuid.FromStringOrNil(request.UUIDStr)
|
||||
if componentUUID == uuid.Nil {
|
||||
err := fmt.Errorf("convert component uuid failed")
|
||||
logger.Error(c, "convert component uuid type from string to uuid failed", "error", err)
|
||||
identifiers := make([]orm.ProjectIdentifier, len(request.AttributeConfigs))
|
||||
attriModifyConfs := make([]attributeModifyConfig, len(request.AttributeConfigs))
|
||||
|
||||
resp := network.FailureResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
Msg: err.Error(),
|
||||
var attributeComponentTag string
|
||||
for index, attribute := range request.AttributeConfigs {
|
||||
slices := strings.Split(attribute.AttributeToken, ".")
|
||||
if len(slices) < 7 {
|
||||
err := fmt.Errorf("index:%d's attribute token format is invalid: %s", index, attribute.AttributeToken)
|
||||
logger.Error(c, "parse attribute token failed", "error", err)
|
||||
resp := network.FailureResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
Msg: "parse attribute token failed",
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
|
||||
componentTag := slices[4]
|
||||
extendName := slices[5]
|
||||
if index == 0 {
|
||||
attributeComponentTag = componentTag
|
||||
}
|
||||
if componentTag != attributeComponentTag {
|
||||
err := fmt.Errorf("batch update across multiple components is not allowed: [%s] vs [%s]", attributeComponentTag, componentTag)
|
||||
logger.Error(c, "attribute consistency check failed", "error", err)
|
||||
|
||||
resp := network.FailureResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
Msg: "all attributes must belong to the same component tag",
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
|
||||
attriModifyConfs[index] = attributeModifyConfig{
|
||||
attributeExtendName: extendName,
|
||||
attributeName: slices[6],
|
||||
attributeOldVal: attribute.AttributeOldVal,
|
||||
attributeNewVal: attribute.AttributeNewVal,
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
|
||||
// open transaction
|
||||
tx := pgClient.Begin()
|
||||
|
||||
componentInfo, err := database.QueryComponentByUUID(c, tx, componentUUID)
|
||||
// query component base info
|
||||
compInfo, err := database.QueryComponentByCompTag(c, tx, attributeComponentTag)
|
||||
if err != nil {
|
||||
logger.Error(c, "query component info by uuid from postgres failed failed", "error", err)
|
||||
logger.Error(c, "query component info by component tag from postgres failed", "error", err)
|
||||
|
||||
tx.Rollback()
|
||||
|
||||
resp := network.FailureResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
Msg: err.Error(),
|
||||
|
|
@ -60,23 +89,76 @@ func ComponentAttributeUpdateHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO 从 project_manager 表进行查询,然后更新对应表的数据的值
|
||||
for i := range attriModifyConfs {
|
||||
identifiers[i] = orm.ProjectIdentifier{
|
||||
Tag: compInfo.ModelName,
|
||||
MetaModel: attriModifyConfs[i].attributeExtendName,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO 更新 redis 中的缓存的数值
|
||||
componentAttributeKey := fmt.Sprintf("%s_%s", componentInfo.Tag, request.AttributeConfigs[0].AttributeExtendType)
|
||||
// attributeSet.CompTag, colParams.AttributeType
|
||||
attributeHSet := diagram.NewRedisHash(c, componentAttributeKey, 5000, false)
|
||||
attributeHSet.SetRedisHashByKV("", nil)
|
||||
// batch retrieve table name mappings
|
||||
tableNameMap, err := database.BatchGetProjectNames(tx, identifiers)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
// TODO 增加错误处理日志
|
||||
return
|
||||
}
|
||||
|
||||
redisUpdateMap := make(map[string][]cacheItem)
|
||||
|
||||
for _, mod := range attriModifyConfs {
|
||||
id := orm.ProjectIdentifier{Tag: compInfo.ModelName, MetaModel: mod.attributeExtendName}
|
||||
tableName, exists := tableNameMap[id]
|
||||
if !exists {
|
||||
// TODO 增加记录警告
|
||||
continue
|
||||
}
|
||||
|
||||
updateErr := tx.Table(tableName).
|
||||
Where(fmt.Sprintf("%s = ?", mod.attributeName), mod.attributeOldVal).
|
||||
Updates(map[string]any{mod.attributeName: mod.attributeNewVal}).Error
|
||||
|
||||
if updateErr != nil {
|
||||
tx.Rollback()
|
||||
// TODO 增加错误处理日志
|
||||
return
|
||||
}
|
||||
|
||||
// init cache item
|
||||
cacheKey := fmt.Sprintf("%s_%s", attributeComponentTag, mod.attributeExtendName)
|
||||
redisUpdateMap[cacheKey] = append(redisUpdateMap[cacheKey], cacheItem{mod.attributeName, mod.attributeNewVal})
|
||||
}
|
||||
|
||||
for key, items := range redisUpdateMap {
|
||||
hset := diagram.NewRedisHash(c, key, 5000, false)
|
||||
for _, item := range items {
|
||||
_ = hset.SetRedisHashByKV(item.name, item.newVal)
|
||||
}
|
||||
}
|
||||
|
||||
// commit transaction
|
||||
tx.Commit()
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp := network.SuccessResponse{
|
||||
Code: http.StatusOK,
|
||||
Msg: "success",
|
||||
Payload: map[string]interface{}{
|
||||
"uuid": request.UUIDStr,
|
||||
"uuid": "",
|
||||
},
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
type attributeModifyConfig struct {
|
||||
attributeExtendName string
|
||||
attributeName string
|
||||
attributeOldVal string
|
||||
attributeNewVal string
|
||||
}
|
||||
|
||||
type cacheItem struct {
|
||||
name string
|
||||
newVal string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,6 @@ func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql
|
|||
if duration > l.SlowThreshold.Milliseconds() {
|
||||
Warn(ctx, "SQL SLOW", "sql", sql, "rows", rows, "dur(ms)", duration)
|
||||
} else {
|
||||
Debug(ctx, "SQL DEBUG", "sql", sql, "rows", rows, "dur(ms)", duration)
|
||||
Info(ctx, "SQL INFO", "sql", sql, "rows", rows, "dur(ms)", duration)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,12 @@ package network
|
|||
|
||||
// ComponentAttributeUpdateInfo defines circuit diagram component attribute params info
|
||||
type ComponentAttributeUpdateInfo struct {
|
||||
UUIDStr string `json:"uuid"`
|
||||
AttributeConfigs []ComponentAttributeConfig `json:"attributes"`
|
||||
}
|
||||
|
||||
// ComponentAttributeConfig defines request params of circuit diagram component attribute update config
|
||||
type ComponentAttributeConfig struct {
|
||||
AttributeExtendType string `json:"attribute_extend_type"`
|
||||
AttributeName string `json:"attribute_name"`
|
||||
AttributeVal string `json:"attribute_val"`
|
||||
AttributeFieldType string `json:"attribute_field_type"`
|
||||
AttributeToken string `json:"token"`
|
||||
AttributeOldVal string `json:"attribute_old_val"`
|
||||
AttributeNewVal string `json:"attribute_new_val"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,3 +17,9 @@ type ProjectManager struct {
|
|||
func (p *ProjectManager) TableName() string {
|
||||
return "project_manager"
|
||||
}
|
||||
|
||||
// ProjectIdentifier define struct to encapsulate query parameter pairs
|
||||
type ProjectIdentifier struct {
|
||||
Tag string
|
||||
MetaModel string
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue