215 lines
6.3 KiB
Go
215 lines
6.3 KiB
Go
// Package handler provides HTTP handlers for various endpoints.
|
|
package handler
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"modelRT/common/errcode"
|
|
"modelRT/constants"
|
|
"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 request params failed", "error", err)
|
|
renderRespFailure(c, constants.RespCodeInvalidParams, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
updateResults := make(map[string]*errcode.AppError)
|
|
attriModifyConfs := make([]attributeModifyConfig, 0, len(request.AttributeConfigs))
|
|
var attributeComponentTag string
|
|
for index, attribute := range request.AttributeConfigs {
|
|
slices := strings.Split(attribute.AttributeToken, ".")
|
|
if len(slices) < 7 {
|
|
updateResults[attribute.AttributeToken] = errcode.ErrInvalidToken
|
|
continue
|
|
}
|
|
|
|
componentTag := slices[4]
|
|
if index == 0 {
|
|
attributeComponentTag = componentTag
|
|
} else if componentTag != attributeComponentTag {
|
|
updateResults[attribute.AttributeToken] = errcode.ErrCrossToken
|
|
continue
|
|
}
|
|
|
|
attriModifyConfs = append(attriModifyConfs, attributeModifyConfig{
|
|
attributeToken: attribute.AttributeToken,
|
|
attributeExtendType: slices[5],
|
|
attributeName: slices[6],
|
|
attributeOldVal: attribute.AttributeOldVal,
|
|
attributeNewVal: attribute.AttributeNewVal,
|
|
})
|
|
}
|
|
|
|
// open transaction
|
|
tx := pgClient.WithContext(c).Begin()
|
|
if tx.Error != nil {
|
|
logger.Error(c, "begin postgres transaction failed", "error", tx.Error)
|
|
renderRespFailure(c, constants.RespCodeServerError, "begin postgres transaction failed", nil)
|
|
return
|
|
}
|
|
|
|
compInfo, err := database.QueryComponentByCompTag(c, tx, attributeComponentTag)
|
|
if err != nil {
|
|
logger.Error(c, "query component info by component tag failed", "error", err, "tag", attributeComponentTag)
|
|
|
|
for _, attribute := range request.AttributeConfigs {
|
|
if _, exists := updateResults[attribute.AttributeToken]; !exists {
|
|
updateResults[attribute.AttributeToken] = errcode.ErrDBQueryFailed.WithCause(err)
|
|
}
|
|
}
|
|
|
|
tx.Rollback()
|
|
|
|
payload := genUpdateRespPayload(updateResults, request.AttributeConfigs)
|
|
renderRespFailure(c, constants.RespCodeFailed, "query component metadata failed", payload)
|
|
return
|
|
}
|
|
|
|
identifiers := make([]orm.ProjectIdentifier, len(attriModifyConfs))
|
|
for i, mod := range attriModifyConfs {
|
|
identifiers[i] = orm.ProjectIdentifier{
|
|
Token: mod.attributeToken,
|
|
Tag: compInfo.ModelName,
|
|
GroupName: mod.attributeExtendType,
|
|
}
|
|
}
|
|
tableNameMap, err := database.BatchGetProjectNames(tx, identifiers)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
|
|
for _, id := range identifiers {
|
|
if _, exists := updateResults[id.Token]; !exists {
|
|
updateResults[id.Token] = errcode.ErrRetrieveFailed.WithCause(err)
|
|
}
|
|
}
|
|
|
|
payload := genUpdateRespPayload(updateResults, request.AttributeConfigs)
|
|
renderRespFailure(c, constants.RespCodeFailed, "batch retrieve table names failed", payload)
|
|
return
|
|
}
|
|
|
|
redisUpdateMap := make(map[string][]cacheUpdateItem)
|
|
for _, mod := range attriModifyConfs {
|
|
id := orm.ProjectIdentifier{Tag: compInfo.ModelName, GroupName: mod.attributeExtendType}
|
|
tableName, exists := tableNameMap[id]
|
|
if !exists {
|
|
updateResults[mod.attributeToken] = errcode.ErrFoundTargetFailed
|
|
continue
|
|
}
|
|
|
|
result := tx.Table(tableName).
|
|
Where(fmt.Sprintf("%s = ? AND global_uuid = ?", mod.attributeName), mod.attributeOldVal, compInfo.GlobalUUID).
|
|
Updates(map[string]any{mod.attributeName: mod.attributeNewVal})
|
|
|
|
if result.Error != nil {
|
|
updateResults[mod.attributeToken] = errcode.ErrDBUpdateFailed
|
|
continue
|
|
}
|
|
if result.RowsAffected == 0 {
|
|
updateResults[mod.attributeToken] = errcode.ErrDBzeroAffectedRows
|
|
continue
|
|
}
|
|
|
|
cacheKey := fmt.Sprintf("%s_%s", attributeComponentTag, mod.attributeExtendType)
|
|
redisUpdateMap[cacheKey] = append(redisUpdateMap[cacheKey],
|
|
cacheUpdateItem{
|
|
token: mod.attributeToken,
|
|
name: mod.attributeName,
|
|
newVal: mod.attributeNewVal,
|
|
})
|
|
}
|
|
|
|
// commit transaction
|
|
if err := tx.Commit().Error; err != nil {
|
|
renderRespFailure(c, constants.RespCodeServerError, "transaction commit failed", nil)
|
|
return
|
|
}
|
|
|
|
for key, items := range redisUpdateMap {
|
|
hset := diagram.NewRedisHash(c, key, 5000, false)
|
|
|
|
fields := make(map[string]any, len(items))
|
|
for _, item := range items {
|
|
fields[item.name] = item.newVal
|
|
}
|
|
|
|
if err := hset.SetRedisHashByMap(fields); err != nil {
|
|
logger.Error(c, "batch sync redis failed", "hash_key", key, "error", err)
|
|
|
|
for _, item := range items {
|
|
if _, exists := updateResults[item.token]; exists {
|
|
updateResults[item.token] = errcode.ErrCacheSyncWarn.WithCause(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
payload := genUpdateRespPayload(updateResults, request.AttributeConfigs)
|
|
if len(updateResults) > 0 {
|
|
renderRespFailure(c, constants.RespCodeFailed, "process completed with partial failures", payload)
|
|
return
|
|
}
|
|
renderRespSuccess(c, constants.RespCodeSuccess, "process completed successfully", payload)
|
|
}
|
|
|
|
type attributeModifyConfig struct {
|
|
attributeToken string
|
|
attributeExtendType string
|
|
attributeName string
|
|
attributeOldVal string
|
|
attributeNewVal string
|
|
}
|
|
|
|
type cacheUpdateItem struct {
|
|
token string
|
|
name string
|
|
newVal string
|
|
}
|
|
|
|
type attributeUpdateResult struct {
|
|
Token string `json:"token"`
|
|
Code int `json:"code"`
|
|
Msg string `json:"msg"`
|
|
}
|
|
|
|
func genUpdateRespPayload(updateResults map[string]*errcode.AppError, originalRequests []network.ComponentAttributeConfig) map[string]any {
|
|
attributes := make([]attributeUpdateResult, 0, len(originalRequests))
|
|
|
|
for _, req := range originalRequests {
|
|
token := req.AttributeToken
|
|
|
|
if appErr, exists := updateResults[token]; exists {
|
|
attributes = append(attributes, attributeUpdateResult{
|
|
Token: token,
|
|
Code: appErr.Code(),
|
|
Msg: appErr.Msg(),
|
|
})
|
|
} else {
|
|
attributes = append(attributes, attributeUpdateResult{
|
|
Token: token,
|
|
Code: constants.CodeSuccess,
|
|
Msg: "token value update success",
|
|
})
|
|
}
|
|
}
|
|
|
|
payload := map[string]any{
|
|
"attributes": attributes,
|
|
}
|
|
|
|
return payload
|
|
}
|