2026-01-05 17:20:41 +08:00
|
|
|
// Package handler provides HTTP handlers for various endpoints.
|
|
|
|
|
package handler
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"net/http"
|
2026-01-08 17:34:44 +08:00
|
|
|
"strings"
|
2026-01-05 17:20:41 +08:00
|
|
|
|
|
|
|
|
"modelRT/database"
|
|
|
|
|
"modelRT/diagram"
|
|
|
|
|
"modelRT/logger"
|
|
|
|
|
"modelRT/network"
|
2026-01-08 17:34:44 +08:00
|
|
|
"modelRT/orm"
|
2026-01-05 17:20:41 +08:00
|
|
|
|
|
|
|
|
"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
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 17:34:44 +08:00
|
|
|
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
|
|
|
|
|
}
|
2026-01-05 17:20:41 +08:00
|
|
|
|
2026-01-08 17:34:44 +08:00
|
|
|
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,
|
2026-01-05 17:20:41 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// open transaction
|
|
|
|
|
tx := pgClient.Begin()
|
|
|
|
|
|
2026-01-08 17:34:44 +08:00
|
|
|
// query component base info
|
|
|
|
|
compInfo, err := database.QueryComponentByCompTag(c, tx, attributeComponentTag)
|
2026-01-05 17:20:41 +08:00
|
|
|
if err != nil {
|
2026-01-08 17:34:44 +08:00
|
|
|
logger.Error(c, "query component info by component tag from postgres failed", "error", err)
|
2026-01-05 17:20:41 +08:00
|
|
|
|
|
|
|
|
tx.Rollback()
|
|
|
|
|
resp := network.FailureResponse{
|
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
|
Msg: err.Error(),
|
|
|
|
|
}
|
|
|
|
|
c.JSON(http.StatusOK, resp)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 17:34:44 +08:00
|
|
|
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)
|
2026-01-05 17:20:41 +08:00
|
|
|
|
2026-01-08 17:34:44 +08:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-05 17:20:41 +08:00
|
|
|
|
|
|
|
|
// commit transaction
|
2026-01-08 17:34:44 +08:00
|
|
|
if err := tx.Commit().Error; err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-01-05 17:20:41 +08:00
|
|
|
|
|
|
|
|
resp := network.SuccessResponse{
|
|
|
|
|
Code: http.StatusOK,
|
|
|
|
|
Msg: "success",
|
|
|
|
|
Payload: map[string]interface{}{
|
2026-01-08 17:34:44 +08:00
|
|
|
"uuid": "",
|
2026-01-05 17:20:41 +08:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
c.JSON(http.StatusOK, resp)
|
|
|
|
|
}
|
2026-01-08 17:34:44 +08:00
|
|
|
|
|
|
|
|
type attributeModifyConfig struct {
|
|
|
|
|
attributeExtendName string
|
|
|
|
|
attributeName string
|
|
|
|
|
attributeOldVal string
|
|
|
|
|
attributeNewVal string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type cacheItem struct {
|
|
|
|
|
name string
|
|
|
|
|
newVal string
|
|
|
|
|
}
|