2024-11-22 16:41:04 +08:00
// Package database define database operation functions
package database
import (
"context"
2025-05-13 16:34:25 +08:00
"fmt"
2024-11-22 16:41:04 +08:00
"time"
2025-05-13 16:34:25 +08:00
"modelRT/constant"
2024-11-27 09:11:48 +08:00
"modelRT/diagram"
2024-11-22 16:41:04 +08:00
"modelRT/orm"
2024-12-03 16:38:17 +08:00
"modelRT/sql"
2024-11-22 16:41:04 +08:00
2024-11-27 09:11:48 +08:00
"github.com/gofrs/uuid"
2024-11-22 16:41:04 +08:00
"go.uber.org/zap"
2025-01-09 15:56:40 +08:00
"gorm.io/gorm"
2024-11-22 16:41:04 +08:00
"gorm.io/gorm/clause"
)
2025-05-13 16:34:25 +08:00
// QueryTopologic return the topologic info of the circuit diagram
func QueryTopologic ( ctx context . Context , tx * gorm . DB , logger * zap . Logger ) ( [ ] orm . Topologic , error ) {
2024-11-22 16:41:04 +08:00
var topologics [ ] orm . Topologic
// ctx超时判断
cancelCtx , cancel := context . WithTimeout ( ctx , 5 * time . Second )
defer cancel ( )
2025-01-09 15:56:40 +08:00
2025-05-16 14:24:55 +08:00
result := tx . WithContext ( cancelCtx ) . Clauses ( clause . Locking { Strength : "UPDATE" } ) . Raw ( sql . RecursiveSQL , constant . UUIDNilStr ) . Scan ( & topologics )
2024-11-22 16:41:04 +08:00
if result . Error != nil {
2025-05-16 14:24:55 +08:00
logger . Error ( "query circuit diagram topologic info by start node uuid failed" , zap . String ( "start_node_uuid" , constant . UUIDNilStr ) , zap . Error ( result . Error ) )
2024-11-22 16:41:04 +08:00
return nil , result . Error
}
return topologics , nil
}
2025-05-13 16:34:25 +08:00
// QueryTopologicFromDB return the result of query topologic info from DB
func QueryTopologicFromDB ( ctx context . Context , tx * gorm . DB , logger * zap . Logger , componentTypeMap map [ uuid . UUID ] int ) error {
topologicInfos , err := QueryTopologic ( ctx , tx , logger )
2024-11-27 09:11:48 +08:00
if err != nil {
2025-05-13 16:34:25 +08:00
logger . Error ( "query topologic info failed" , zap . Error ( err ) )
return err
2024-11-27 09:11:48 +08:00
}
2025-05-13 16:34:25 +08:00
// err = InitCircuitDiagramTopologic(topologicInfos, componentTypeMap)
// if err != nil {
// logger.Error("init topologic failed", zap.Error(err))
// return err
// }
2025-01-09 15:56:40 +08:00
2025-05-13 16:34:25 +08:00
_ , err = BuildMultiBranchTree ( topologicInfos , componentTypeMap )
if err != nil {
logger . Error ( "init topologic failed" , zap . Error ( err ) )
return err
2024-11-27 09:11:48 +08:00
}
2025-05-13 16:34:25 +08:00
return nil
2024-11-22 16:41:04 +08:00
}
2024-12-03 16:38:17 +08:00
// InitCircuitDiagramTopologic return circuit diagram topologic info from postgres
2025-05-13 16:34:25 +08:00
func InitCircuitDiagramTopologic ( topologicNodes [ ] orm . Topologic , componentTypeMap map [ uuid . UUID ] int ) error {
var rootVertex * diagram . MultiBranchTreeNode
2024-12-03 16:38:17 +08:00
for _ , node := range topologicNodes {
2025-05-16 14:24:55 +08:00
if node . UUIDFrom == constant . UUIDNil {
2025-05-13 16:34:25 +08:00
// rootVertex = node.UUIDTo
var componentType int
componentType , ok := componentTypeMap [ node . UUIDFrom ]
if ! ok {
return fmt . Errorf ( "can not get component type by uuid: %s" , node . UUIDFrom )
}
rootVertex = diagram . NewMultiBranchTree ( node . UUIDFrom , componentType )
2024-12-03 16:38:17 +08:00
break
}
}
2025-05-13 16:34:25 +08:00
if rootVertex == nil {
return fmt . Errorf ( "root vertex is nil" )
}
2024-12-03 16:38:17 +08:00
for _ , node := range topologicNodes {
2025-05-16 14:24:55 +08:00
if node . UUIDFrom == constant . UUIDNil {
2025-05-13 16:34:25 +08:00
var componentType int
componentType , ok := componentTypeMap [ node . UUIDTo ]
if ! ok {
return fmt . Errorf ( "can not get component type by uuid: %s" , node . UUIDTo )
}
nodeVertex := diagram . NewMultiBranchTree ( node . UUIDTo , componentType )
rootVertex . AddChild ( nodeVertex )
2024-12-03 16:38:17 +08:00
}
}
2025-05-13 16:34:25 +08:00
node := rootVertex
for _ , nodeVertex := range node . Children {
nextVertexs := make ( [ ] * diagram . MultiBranchTreeNode , 0 )
nextVertexs = append ( nextVertexs , nodeVertex )
}
2024-12-03 16:38:17 +08:00
return nil
}
2025-04-30 16:44:58 +08:00
2025-05-16 14:24:55 +08:00
// TODO 电流互感器不单独划分间隔
// TODO 以母线、浇筑母线、变压器为间隔原件
2025-05-13 16:34:25 +08:00
func IntervalBoundaryDetermine ( uuid uuid . UUID ) bool {
2025-04-30 16:44:58 +08:00
// TODO 从diagramsOverview中根据 uuid 获取 component 信息
var componentID int64
diagram . GetComponentMap ( componentID )
// TODO 判断 component 的类型是否为间隔
2025-05-16 14:24:55 +08:00
// TODO 0x1111A1B2C3D4,高四位表示可以成为间隔的compoent类型的值为FFFF,普通 component 类型的值为 0000。低四位中前二位表示component的一级类型, 例如母线 PT、母联/母分、进线等,低四位中后二位表示一级类型中包含的具体类型,例如母线 PT中包含的电压互感器、隔离开关、接地开关、避雷器、带电显示器等。
num := uint32 ( 0xA1B2C3D4 ) // 八位16进制数
high16 := uint16 ( num >> 16 )
fmt . Printf ( "原始值: 0x%X\n" , num ) // 输出: 0xA1B2C3D4
fmt . Printf ( "高十六位: 0x%X\n" , high16 ) // 输出: 0xA1B2
2025-04-30 16:44:58 +08:00
return true
}
2025-05-13 16:34:25 +08:00
// BuildMultiBranchTree return the multi branch tree by topologic info and component type map
func BuildMultiBranchTree ( topologics [ ] orm . Topologic , componentTypeMap map [ uuid . UUID ] int ) ( * diagram . MultiBranchTreeNode , error ) {
nodeMap := make ( map [ uuid . UUID ] * diagram . MultiBranchTreeNode , len ( topologics ) )
for _ , topo := range topologics {
// skip special uuid
2025-05-16 14:24:55 +08:00
if _ , exists := nodeMap [ topo . UUIDFrom ] ; ! exists {
var componentType int
if topo . UUIDTo != constant . UUIDNil {
var ok bool
componentType , ok = componentTypeMap [ topo . UUIDFrom ]
2025-05-13 16:34:25 +08:00
if ! ok {
return nil , fmt . Errorf ( "can not get component type by uuid: %s" , topo . UUIDFrom )
}
nodeMap [ topo . UUIDFrom ] = & diagram . MultiBranchTreeNode {
ID : topo . UUIDFrom ,
NodeComponentType : componentType ,
}
}
}
if _ , exists := nodeMap [ topo . UUIDTo ] ; ! exists {
2025-05-16 14:24:55 +08:00
var componentType int
if topo . UUIDTo != constant . UUIDNil {
var ok bool
componentType , ok = componentTypeMap [ topo . UUIDTo ]
if ! ok {
return nil , fmt . Errorf ( "can not get component type by uuid: %s" , topo . UUIDTo )
}
2025-05-13 16:34:25 +08:00
}
nodeMap [ topo . UUIDTo ] = & diagram . MultiBranchTreeNode {
ID : topo . UUIDTo ,
NodeComponentType : componentType ,
}
}
}
for _ , topo := range topologics {
var parent * diagram . MultiBranchTreeNode
2025-05-16 14:24:55 +08:00
if topo . UUIDFrom == constant . UUIDNil {
var componentType int
2025-05-13 16:34:25 +08:00
parent = & diagram . MultiBranchTreeNode {
2025-05-16 14:24:55 +08:00
ID : constant . UUIDNil ,
2025-05-13 16:34:25 +08:00
NodeComponentType : componentType ,
}
2025-05-16 14:24:55 +08:00
nodeMap [ constant . UUIDNil ] = parent
2025-05-13 16:34:25 +08:00
} else {
parent = nodeMap [ topo . UUIDFrom ]
}
child := nodeMap [ topo . UUIDTo ]
child . Parent = parent
parent . Children = append ( parent . Children , child )
}
// return root vertex
2025-05-16 14:24:55 +08:00
root , exists := nodeMap [ constant . UUIDNil ]
2025-05-13 16:34:25 +08:00
if ! exists {
return nil , fmt . Errorf ( "root node not found" )
}
return root , nil
}