// Package database define database operation functions package database import ( "context" "fmt" "time" "modelRT/constants" "modelRT/diagram" "modelRT/logger" "modelRT/orm" "modelRT/sql" "github.com/gofrs/uuid" "gorm.io/gorm" "gorm.io/gorm/clause" ) // QueryTopologic return the topologic info of the circuit diagram func QueryTopologic(ctx context.Context, tx *gorm.DB) ([]orm.Topologic, error) { var topologics []orm.Topologic // ctx超时判断 cancelCtx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() result := tx.WithContext(cancelCtx).Clauses(clause.Locking{Strength: "UPDATE"}).Raw(sql.RecursiveSQL, constants.UUIDNilStr).Scan(&topologics) if result.Error != nil { logger.Error(ctx, "query circuit diagram topologic info by start node uuid failed", "start_node_uuid", constants.UUIDNilStr, "error", result.Error) return nil, result.Error } return topologics, nil } // QueryTopologicFromDB return the result of query topologic info from DB func QueryTopologicFromDB(ctx context.Context, tx *gorm.DB) (*diagram.MultiBranchTreeNode, error) { topologicInfos, err := QueryTopologic(ctx, tx) if err != nil { logger.Error(ctx, "query topologic info failed", "error", err) return nil, err } tree, err := BuildMultiBranchTree(topologicInfos) if err != nil { logger.Error(ctx, "init topologic failed", "error", err) return nil, err } return tree, nil } // InitCircuitDiagramTopologic return circuit diagram topologic info from postgres func InitCircuitDiagramTopologic(topologicNodes []orm.Topologic) error { var rootVertex *diagram.MultiBranchTreeNode for _, node := range topologicNodes { if node.UUIDFrom == constants.UUIDNil { rootVertex = diagram.NewMultiBranchTree(node.UUIDFrom) break } } if rootVertex == nil { return fmt.Errorf("root vertex is nil") } for _, node := range topologicNodes { if node.UUIDFrom == constants.UUIDNil { nodeVertex := diagram.NewMultiBranchTree(node.UUIDTo) rootVertex.AddChild(nodeVertex) } } node := rootVertex for _, nodeVertex := range node.Children { nextVertexs := make([]*diagram.MultiBranchTreeNode, 0) nextVertexs = append(nextVertexs, nodeVertex) } return nil } // TODO 电流互感器不单独划分间隔,以母线、浇筑母线、变压器为间隔原件 func IntervalBoundaryDetermine(uuid uuid.UUID) bool { diagram.GetComponentMap(uuid.String()) // TODO 判断 component 的类型是否为间隔 // TODO 0xA1B2C3D4,高四位表示可以成为间隔的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 return true } // BuildMultiBranchTree return the multi branch tree by topologic info and component type map func BuildMultiBranchTree(topologics []orm.Topologic) (*diagram.MultiBranchTreeNode, error) { nodeMap := make(map[uuid.UUID]*diagram.MultiBranchTreeNode, len(topologics)*2) for _, topo := range topologics { if _, exists := nodeMap[topo.UUIDFrom]; !exists { // skip special uuid if topo.UUIDTo != constants.UUIDNil { nodeMap[topo.UUIDFrom] = &diagram.MultiBranchTreeNode{ ID: topo.UUIDFrom, Children: make([]*diagram.MultiBranchTreeNode, 0), } } } if _, exists := nodeMap[topo.UUIDTo]; !exists { // skip special uuid if topo.UUIDTo != constants.UUIDNil { nodeMap[topo.UUIDTo] = &diagram.MultiBranchTreeNode{ ID: topo.UUIDTo, Children: make([]*diagram.MultiBranchTreeNode, 0), } } } } for _, topo := range topologics { var parent *diagram.MultiBranchTreeNode if topo.UUIDFrom == constants.UUIDNil { parent = &diagram.MultiBranchTreeNode{ ID: constants.UUIDNil, } nodeMap[constants.UUIDNil] = parent } else { parent = nodeMap[topo.UUIDFrom] } var child *diagram.MultiBranchTreeNode if topo.UUIDTo == constants.UUIDNil { child = &diagram.MultiBranchTreeNode{ ID: topo.UUIDTo, } } else { child = nodeMap[topo.UUIDTo] } child.Parent = parent parent.Children = append(parent.Children, child) } // return root vertex root, exists := nodeMap[constants.UUIDNil] if !exists { return nil, fmt.Errorf("root node not found") } return root, nil }