refactor(topologic storage struct): refactor topologic storage struct
1.refactor topologic storage struct by multi branch tree
2.add new func of build multi branch tree
3.modify sql of query topologic from db
4.delete page id field from topologic struct
This commit is contained in:
parent
af0cfce78f
commit
daf30766ba
|
|
@ -1,5 +1,7 @@
|
|||
package constant
|
||||
|
||||
import "github.com/gofrs/uuid"
|
||||
|
||||
const (
|
||||
// UUIDErrChangeType 拓扑信息错误改变类型
|
||||
UUIDErrChangeType = iota
|
||||
|
|
@ -10,3 +12,11 @@ const (
|
|||
// UUIDAddChangeType 拓扑信息新增类型
|
||||
UUIDAddChangeType
|
||||
)
|
||||
|
||||
const (
|
||||
// SpecialUUIDStr 拓扑信息中开始节点与结束节点字符串形式
|
||||
SpecialUUIDStr = "00000000-0000-0000-0000-000000000000"
|
||||
)
|
||||
|
||||
// SpecialUUID 拓扑信息中开始节点与结束节点 UUID 格式
|
||||
var SpecialUUID = uuid.FromStringOrNil(SpecialUUIDStr)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ func CreateTopologicIntoDB(ctx context.Context, tx *gorm.DB, pageID int64, topol
|
|||
var topologicSlice []orm.Topologic
|
||||
for _, info := range topologicInfos {
|
||||
topologicInfo := orm.Topologic{
|
||||
PageID: pageID,
|
||||
UUIDFrom: info.UUIDFrom,
|
||||
UUIDTo: info.UUIDTo,
|
||||
Flag: info.Flag,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ func QueryCircuitDiagramComponentFromDB(ctx context.Context, tx *gorm.DB, pool *
|
|||
return nil, result.Error
|
||||
}
|
||||
|
||||
// TODO 优化componentTypeMap输出
|
||||
componentTypeMap := make(map[uuid.UUID]int, len(components))
|
||||
|
||||
for _, component := range components {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ package database
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"modelRT/constant"
|
||||
"modelRT/diagram"
|
||||
"modelRT/orm"
|
||||
"modelRT/sql"
|
||||
|
|
@ -15,16 +17,16 @@ import (
|
|||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// QueryTopologicByPageID return the topologic info of the circuit diagram query by pageID
|
||||
func QueryTopologicByPageID(ctx context.Context, tx *gorm.DB, logger *zap.Logger, pageID int64) ([]orm.Topologic, error) {
|
||||
// QueryTopologic return the topologic info of the circuit diagram
|
||||
func QueryTopologic(ctx context.Context, tx *gorm.DB, logger *zap.Logger) ([]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, pageID).Scan(&topologics)
|
||||
result := tx.WithContext(cancelCtx).Clauses(clause.Locking{Strength: "UPDATE"}).Raw(sql.RecursiveSQL, constant.SpecialUUIDStr).Scan(&topologics)
|
||||
if result.Error != nil {
|
||||
logger.Error("query circuit diagram topologic info by pageID failed", zap.Int64("pageID", pageID), zap.Error(result.Error))
|
||||
logger.Error("query circuit diagram topologic info by start node uuid failed", zap.String("start_node_uuid", constant.SpecialUUIDStr), zap.Error(result.Error))
|
||||
return nil, result.Error
|
||||
}
|
||||
return topologics, nil
|
||||
|
|
@ -32,58 +34,136 @@ func QueryTopologicByPageID(ctx context.Context, tx *gorm.DB, logger *zap.Logger
|
|||
|
||||
// TODO 电流互感器不单独划分间隔
|
||||
// TODO 以母线、浇筑母线、变压器为间隔原件
|
||||
// QueryTopologicFromDB return the result of query topologic info from postgresDB
|
||||
func QueryTopologicFromDB(ctx context.Context, tx *gorm.DB, logger *zap.Logger, gridID, zoneID, stationID int64) ([]orm.Page, error) {
|
||||
allPages, err := QueryAllPages(ctx, tx, logger, gridID, zoneID, stationID)
|
||||
// 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)
|
||||
if err != nil {
|
||||
logger.Error("query all pages info failed", zap.Int64("gridID", gridID), zap.Int64("zoneID", zoneID), zap.Int64("stationID", stationID), zap.Error(err))
|
||||
return nil, err
|
||||
logger.Error("query topologic info failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
for _, page := range allPages {
|
||||
topologicInfos, err := QueryTopologicByPageID(ctx, tx, logger, page.ID)
|
||||
if err != nil {
|
||||
logger.Error("query topologic info by pageID failed", zap.Int64("pageID", page.ID), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
// err = InitCircuitDiagramTopologic(topologicInfos, componentTypeMap)
|
||||
// if err != nil {
|
||||
// logger.Error("init topologic failed", zap.Error(err))
|
||||
// return err
|
||||
// }
|
||||
|
||||
err = InitCircuitDiagramTopologic(page.ID, topologicInfos)
|
||||
_, err = BuildMultiBranchTree(topologicInfos, componentTypeMap)
|
||||
if err != nil {
|
||||
logger.Error("init topologic failed", zap.Error(err))
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
return allPages, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitCircuitDiagramTopologic return circuit diagram topologic info from postgres
|
||||
func InitCircuitDiagramTopologic(pageID int64, topologicNodes []orm.Topologic) error {
|
||||
var rootVertex uuid.UUID
|
||||
|
||||
func InitCircuitDiagramTopologic(topologicNodes []orm.Topologic, componentTypeMap map[uuid.UUID]int) error {
|
||||
var rootVertex *diagram.MultiBranchTreeNode
|
||||
for _, node := range topologicNodes {
|
||||
if node.UUIDFrom.IsNil() {
|
||||
rootVertex = node.UUIDTo
|
||||
if node.UUIDFrom == constant.SpecialUUID {
|
||||
// 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)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
topologicSet := diagram.NewGraph(rootVertex)
|
||||
if rootVertex == nil {
|
||||
return fmt.Errorf("root vertex is nil")
|
||||
}
|
||||
|
||||
for _, node := range topologicNodes {
|
||||
if node.UUIDFrom.IsNil() {
|
||||
continue
|
||||
if node.UUIDFrom == constant.SpecialUUID {
|
||||
var componentType int
|
||||
componentType, ok := componentTypeMap[node.UUIDTo]
|
||||
if !ok {
|
||||
return fmt.Errorf("can not get component type by uuid: %s", node.UUIDTo)
|
||||
}
|
||||
// TODO 增加对 node.flag值的判断
|
||||
topologicSet.AddEdge(node.UUIDFrom, node.UUIDTo)
|
||||
nodeVertex := diagram.NewMultiBranchTree(node.UUIDTo, componentType)
|
||||
|
||||
rootVertex.AddChild(nodeVertex)
|
||||
}
|
||||
}
|
||||
|
||||
node := rootVertex
|
||||
for _, nodeVertex := range node.Children {
|
||||
nextVertexs := make([]*diagram.MultiBranchTreeNode, 0)
|
||||
nextVertexs = append(nextVertexs, nodeVertex)
|
||||
}
|
||||
diagram.StoreGraphMap(pageID, topologicSet)
|
||||
return nil
|
||||
}
|
||||
|
||||
func IntervalBoundaryDetermine(pageID int64, uuid uuid.UUID) bool {
|
||||
func IntervalBoundaryDetermine(uuid uuid.UUID) bool {
|
||||
// TODO 从diagramsOverview中根据 uuid 获取 component 信息
|
||||
var componentID int64
|
||||
diagram.GetComponentMap(componentID)
|
||||
// TODO 判断 component 的类型是否为间隔
|
||||
return true
|
||||
}
|
||||
|
||||
// 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
|
||||
if topo.UUIDFrom != constant.SpecialUUID {
|
||||
if _, exists := nodeMap[topo.UUIDFrom]; !exists {
|
||||
componentType, ok := componentTypeMap[topo.UUIDFrom]
|
||||
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 {
|
||||
componentType, ok := componentTypeMap[topo.UUIDTo]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("can not get component type by uuid: %s", topo.UUIDTo)
|
||||
}
|
||||
|
||||
nodeMap[topo.UUIDTo] = &diagram.MultiBranchTreeNode{
|
||||
ID: topo.UUIDTo,
|
||||
NodeComponentType: componentType,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, topo := range topologics {
|
||||
var parent *diagram.MultiBranchTreeNode
|
||||
if topo.UUIDFrom == constant.SpecialUUID {
|
||||
componentType, ok := componentTypeMap[topo.UUIDTo]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("can not get component type by uuid: %s", topo.UUIDTo)
|
||||
}
|
||||
|
||||
parent = &diagram.MultiBranchTreeNode{
|
||||
ID: constant.SpecialUUID,
|
||||
NodeComponentType: componentType,
|
||||
}
|
||||
nodeMap[constant.SpecialUUID] = parent
|
||||
} else {
|
||||
parent = nodeMap[topo.UUIDFrom]
|
||||
}
|
||||
|
||||
child := nodeMap[topo.UUIDTo]
|
||||
child.Parent = parent
|
||||
parent.Children = append(parent.Children, child)
|
||||
}
|
||||
|
||||
// return root vertex
|
||||
root, exists := nodeMap[constant.SpecialUUID]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("root node not found")
|
||||
}
|
||||
return root, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ func UpdateTopologicIntoDB(ctx context.Context, tx *gorm.DB, pageID int64, chang
|
|||
result = tx.WithContext(cancelCtx).Model(&orm.Topologic{}).Where("page_id = ? and uuid_from = ? and uuid_to = ?", pageID, changeInfo.OldUUIDFrom, changeInfo.OldUUIDTo).Updates(&orm.Topologic{UUIDTo: changeInfo.NewUUIDTo})
|
||||
case constant.UUIDAddChangeType:
|
||||
topologic := orm.Topologic{
|
||||
PageID: pageID,
|
||||
Flag: changeInfo.Flag,
|
||||
UUIDFrom: changeInfo.NewUUIDFrom,
|
||||
UUIDTo: changeInfo.NewUUIDTo,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
package diagram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
)
|
||||
|
||||
// MultiBranchTreeNode represents a topological structure using an multi branch tree
|
||||
type MultiBranchTreeNode struct {
|
||||
ID uuid.UUID // 节点唯一标识
|
||||
NodeComponentType int // 节点组件类型
|
||||
Parent *MultiBranchTreeNode // 指向父节点的指针
|
||||
Children []*MultiBranchTreeNode // 指向所有子节点的指针切片
|
||||
}
|
||||
|
||||
func NewMultiBranchTree(id uuid.UUID, componentType int) *MultiBranchTreeNode {
|
||||
return &MultiBranchTreeNode{
|
||||
ID: id,
|
||||
NodeComponentType: componentType,
|
||||
Children: make([]*MultiBranchTreeNode, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *MultiBranchTreeNode) AddChild(child *MultiBranchTreeNode) {
|
||||
child.Parent = n
|
||||
n.Children = append(n.Children, child)
|
||||
}
|
||||
|
||||
func (n *MultiBranchTreeNode) RemoveChild(childID uuid.UUID) bool {
|
||||
for i, child := range n.Children {
|
||||
if child.ID == childID {
|
||||
n.Children = append(n.Children[:i], n.Children[i+1:]...)
|
||||
child.Parent = nil
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *MultiBranchTreeNode) FindNodeByID(id uuid.UUID) *MultiBranchTreeNode {
|
||||
if n.ID == id {
|
||||
return n
|
||||
}
|
||||
|
||||
for _, child := range n.Children {
|
||||
if found := child.FindNodeByID(id); found != nil {
|
||||
return found
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *MultiBranchTreeNode) PrintTree(level int) {
|
||||
for i := 0; i < level; i++ {
|
||||
fmt.Print(" ")
|
||||
}
|
||||
|
||||
fmt.Printf("- ComponentType:%d,(ID: %s)\n", n.NodeComponentType, n.ID)
|
||||
|
||||
for _, child := range n.Children {
|
||||
child.PrintTree(level + 1)
|
||||
}
|
||||
}
|
||||
24
main.go
24
main.go
|
|
@ -4,7 +4,6 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"modelRT/alert"
|
||||
|
|
@ -109,32 +108,11 @@ func main() {
|
|||
}
|
||||
|
||||
// TODO 暂时屏蔽完成 swagger 启动测试
|
||||
// TODO 将componentTypeMap传入QueryTopologicFromDB中
|
||||
pages, err := database.QueryTopologicFromDB(ctx, tx, zapLogger, modelRTConfig.GridID, modelRTConfig.ZoneID, modelRTConfig.StationID)
|
||||
err = database.QueryTopologicFromDB(ctx, tx, zapLogger, componentTypeMap)
|
||||
if err != nil {
|
||||
zapLogger.Error("load topologic info from postgres failed", zap.Error(err))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, page := range pages {
|
||||
graph, err := diagram.GetGraphMap(page.ID)
|
||||
if err != nil {
|
||||
// TODO 增加报错日志错误
|
||||
continue
|
||||
}
|
||||
|
||||
rootNode := graph.RootVertex.String()
|
||||
links := graph.VerticeLinks[rootNode]
|
||||
for {
|
||||
for _, link := range links {
|
||||
fmt.Println(link)
|
||||
}
|
||||
// TODO 重置 links
|
||||
}
|
||||
|
||||
}
|
||||
fmt.Println(componentTypeMap)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import "github.com/gofrs/uuid"
|
|||
// Topologic structure define topologic info set of circuit diagram
|
||||
type Topologic struct {
|
||||
ID int64 `gorm:"column:id"`
|
||||
PageID int64 `gorm:"column:page_id"`
|
||||
Flag int `gorm:"column:flag"`
|
||||
UUIDFrom uuid.UUID `gorm:"column:uuid_from"`
|
||||
UUIDTo uuid.UUID `gorm:"column:uuid_to"`
|
||||
|
|
|
|||
|
|
@ -3,15 +3,12 @@ package sql
|
|||
|
||||
// RecursiveSQL define Topologic table recursive query statement
|
||||
var RecursiveSQL = `WITH RECURSIVE recursive_tree as (
|
||||
SELECT uuid_from,uuid_to,page_id,flag
|
||||
SELECT uuid_from,uuid_to,flag
|
||||
FROM "Topologic"
|
||||
WHERE uuid_from is null and page_id = ?
|
||||
WHERE uuid_from = ?
|
||||
UNION ALL
|
||||
SELECT t.uuid_from,t.uuid_to,t.page_id,t.flag
|
||||
FROM "Topologic" t
|
||||
JOIN recursive_tree rt ON t.uuid_from = rt.uuid_to
|
||||
)
|
||||
SELECT * FROM recursive_tree;`
|
||||
|
||||
// TODO 为 Topologic 表增加唯一索引
|
||||
// CREATE UNIQUE INDEX uuid_from_to_page_id_idx ON public."Topologic"(uuid_from,uuid_to,page_id);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ func TestMain(m *testing.M) {
|
|||
|
||||
func TestUserDao_CreateUser(t *testing.T) {
|
||||
topologicInfo := &orm.Topologic{
|
||||
PageID: 1,
|
||||
UUIDFrom: uuid.FromStringOrNil("70c190f2-8a60-42a9-b143-ec5f87e0aa6b"),
|
||||
UUIDTo: uuid.FromStringOrNil("70c190f2-8a75-42a9-b166-ec5f87e0aa6b"),
|
||||
Comment: "test",
|
||||
|
|
@ -51,7 +50,7 @@ func TestUserDao_CreateUser(t *testing.T) {
|
|||
// ud := dao2.NewUserDao(context.TODO())
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec(regexp.QuoteMeta("INSERT INTO `Topologic`")).
|
||||
WithArgs(topologicInfo.PageID, topologicInfo.Flag, topologicInfo.UUIDFrom, topologicInfo.UUIDTo, topologicInfo.Comment).
|
||||
WithArgs(topologicInfo.Flag, topologicInfo.UUIDFrom, topologicInfo.UUIDTo, topologicInfo.Comment).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue