modelRT/handler/component_attribute_update.go

165 lines
4.3 KiB
Go
Raw Normal View History

// Package handler provides HTTP handlers for various endpoints.
package handler
import (
"fmt"
"net/http"
"strings"
"modelRT/database"
"modelRT/diagram"
"modelRT/logger"
"modelRT/network"
"modelRT/orm"
"github.com/gin-gonic/gin"
)
// 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)
resp := network.FailureResponse{
Code: http.StatusBadRequest,
Msg: err.Error(),
}
c.JSON(http.StatusOK, resp)
return
}
identifiers := make([]orm.ProjectIdentifier, len(request.AttributeConfigs))
attriModifyConfs := make([]attributeModifyConfig, len(request.AttributeConfigs))
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,
}
}
// open transaction
tx := pgClient.Begin()
// query component base info
compInfo, err := database.QueryComponentByCompTag(c, tx, attributeComponentTag)
if err != nil {
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(),
}
c.JSON(http.StatusOK, resp)
return
}
for i := range attriModifyConfs {
identifiers[i] = orm.ProjectIdentifier{
Tag: compInfo.ModelName,
MetaModel: attriModifyConfs[i].attributeExtendName,
}
}
// 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
if err := tx.Commit().Error; err != nil {
return
}
resp := network.SuccessResponse{
Code: http.StatusOK,
Msg: "success",
Payload: map[string]interface{}{
"uuid": "",
},
}
c.JSON(http.StatusOK, resp)
}
type attributeModifyConfig struct {
attributeExtendName string
attributeName string
attributeOldVal string
attributeNewVal string
}
type cacheItem struct {
name string
newVal string
}