diff --git a/kernel/model/graph.go b/kernel/model/graph.go index 3a9c3bc99..30be916f3 100644 --- a/kernel/model/graph.go +++ b/kernel/model/graph.go @@ -93,8 +93,8 @@ func BuildTreeGraph(id, query string) (boxID string, nodes []*GraphNode, links [ var sqlBlocks []*sql.Block var rootID string - if "NodeDocument" == block.Type { - sqlBlocks = sql.GetAllChildBlocks(block.ID, stmt) + if ast.NodeDocument == node.Type { + sqlBlocks = sql.GetAllChildBlocks([]string{block.ID}, stmt) rootID = block.ID } else { sqlBlocks = sql.GetChildBlocks(block.ID, stmt) @@ -106,22 +106,30 @@ func BuildTreeGraph(id, query string) (boxID string, nodes []*GraphNode, links [ if nil != rootBlock { // 按引用处理 sqlRootDefs := sql.QueryDefRootBlocksByRefRootID(rootID) - for _, sqlRootDef := range sqlRootDefs { - rootDef := fromSQLBlock(sqlRootDef, "", 0) + rootDefBlocks := fromSQLBlocks(&sqlRootDefs, "", 0) + var rootIDs []string + for _, rootDef := range rootDefBlocks { blocks = append(blocks, rootDef) + rootIDs = append(rootIDs, rootDef.ID) + } - sqlRootRefs := sql.QueryRefRootBlocksByDefRootID(sqlRootDef.ID) - rootRefs := fromSQLBlocks(&sqlRootRefs, "", 0) - rootDef.Refs = append(rootDef.Refs, rootRefs...) + sqlRootRefBlocks := sql.QueryRefRootBlocksByDefRootIDs(rootIDs) + for defRootID, sqlRefBlocks := range sqlRootRefBlocks { + rootBlock := getBlockIn(rootDefBlocks, defRootID) + if nil == rootBlock { + continue + } + + refBlocks := fromSQLBlocks(&sqlRefBlocks, "", 0) + rootBlock.Refs = append(rootBlock.Refs, refBlocks...) } // 按定义处理 - sqlRootRefs := sql.QueryRefRootBlocksByDefRootID(rootID) - for _, sqlRootRef := range sqlRootRefs { - rootRef := fromSQLBlock(sqlRootRef, "", 0) - blocks = append(blocks, rootRef) - - rootBlock.Refs = append(rootBlock.Refs, rootRef) + sqlRootRefBlocks = sql.QueryRefRootBlocksByDefRootIDs([]string{rootID}) + for _, sqlRefBlocks := range sqlRootRefBlocks { + blocks = append(blocks, rootBlock) + refBlocks := fromSQLBlocks(&sqlRefBlocks, "", 0) + rootBlock.Refs = append(rootBlock.Refs, refBlocks...) } } } @@ -157,22 +165,29 @@ func BuildGraph(query string) (boxID string, nodes []*GraphNode, links []*GraphL if 0 < len(roots) { boxID = roots[0].Box } + var rootIDs []string for _, root := range roots { - sqlBlocks := sql.GetAllChildBlocks(root.ID, stmt) - treeBlocks := fromSQLBlocks(&sqlBlocks, "", 0) - genTreeNodes(treeBlocks, &nodes, &links, false, style) - blocks = append(blocks, treeBlocks...) + rootIDs = append(rootIDs, root.ID) + } + rootIDs = gulu.Str.RemoveDuplicatedElem(rootIDs) - // 文档块关联 - rootBlock := getBlockIn(treeBlocks, root.ID) + sqlBlocks := sql.GetAllChildBlocks(rootIDs, stmt) + treeBlocks := fromSQLBlocks(&sqlBlocks, "", 0) + genTreeNodes(treeBlocks, &nodes, &links, false, style) + blocks = append(blocks, treeBlocks...) + + // 文档块关联 + sqlRootRefBlocks := sql.QueryRefRootBlocksByDefRootIDs(rootIDs) + for defRootID, sqlRefBlocks := range sqlRootRefBlocks { + rootBlock := getBlockIn(treeBlocks, defRootID) if nil == rootBlock { continue } - sqlRootRefs := sql.QueryRefRootBlocksByDefRootID(root.ID) - rootRefs := fromSQLBlocks(&sqlRootRefs, "", 0) - rootBlock.Refs = append(rootBlock.Refs, rootRefs...) + refBlocks := fromSQLBlocks(&sqlRefBlocks, "", 0) + rootBlock.Refs = append(rootBlock.Refs, refBlocks...) } + growTreeGraph(&forwardlinks, &backlinks, &nodes) blocks = append(blocks, forwardlinks...) blocks = append(blocks, backlinks...) @@ -651,6 +666,7 @@ func graphDailyNoteFilter(local bool) string { return "" } + dailyNotesPaths = gulu.Str.RemoveDuplicatedElem(dailyNotesPaths) buf := bytes.Buffer{} for _, p := range dailyNotesPaths { buf.WriteString(" AND ref.hpath NOT LIKE '" + p + "%'") diff --git a/kernel/sql/block_query.go b/kernel/sql/block_query.go index 67886be1d..484752073 100644 --- a/kernel/sql/block_query.go +++ b/kernel/sql/block_query.go @@ -535,13 +535,13 @@ func GetChildBlocks(parentID, condition string) (ret []*Block) { return } -func GetAllChildBlocks(rootID, condition string) (ret []*Block) { +func GetAllChildBlocks(rootIDs []string, condition string) (ret []*Block) { ret = []*Block{} - sqlStmt := "SELECT * FROM blocks AS ref WHERE ref.root_id = ?" + sqlStmt := "SELECT * FROM blocks AS ref WHERE ref.root_id IN ('" + strings.Join(rootIDs, "','") + "')" if "" != condition { sqlStmt += " AND " + condition } - rows, err := query(sqlStmt, rootID) + rows, err := query(sqlStmt) if nil != err { logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err) return diff --git a/kernel/sql/block_ref_query.go b/kernel/sql/block_ref_query.go index c3b81fec6..b938e2049 100644 --- a/kernel/sql/block_ref_query.go +++ b/kernel/sql/block_ref_query.go @@ -157,16 +157,28 @@ func QueryDefRootBlocksByRefRootID(refRootID string) (ret []*Block) { return } -func QueryRefRootBlocksByDefRootID(defRootID string) (ret []*Block) { - rows, err := query("SELECT * FROM blocks WHERE id IN (SELECT DISTINCT root_id FROM refs WHERE def_block_root_id = ?)", defRootID) +func QueryRefRootBlocksByDefRootIDs(defRootIDs []string) (ret map[string][]*Block) { + ret = map[string][]*Block{} + + stmt := "SELECT r.def_block_root_id, b.* FROM refs AS r, blocks AS b ON r.def_block_root_id IN ('" + strings.Join(defRootIDs, "','") + "')" + " AND b.id = r.root_id" + rows, err := query(stmt) if nil != err { logging.LogErrorf("sql query failed: %s", err) return } defer rows.Close() for rows.Next() { - if block := scanBlockRows(rows); nil != block { - ret = append(ret, block) + var block Block + var defRootID string + if err := rows.Scan(&defRootID, &block.ID, &block.ParentID, &block.RootID, &block.Hash, &block.Box, &block.Path, &block.HPath, &block.Name, &block.Alias, &block.Memo, &block.Tag, &block.Content, &block.FContent, &block.Markdown, &block.Length, &block.Type, &block.SubType, &block.IAL, &block.Sort, &block.Created, &block.Updated); nil != err { + logging.LogErrorf("query scan field failed: %s\n%s", err, logging.ShortStack()) + return + } + + if nil == ret[defRootID] { + ret[defRootID] = []*Block{} + } else { + ret[defRootID] = append(ret[defRootID], &block) } } return