From 8de9d03cad67d6944d40567bff90350d132d60b0 Mon Sep 17 00:00:00 2001
From: ai_xiaopei <xiaopei@aisim.cn>
Date: Sun, 26 Jul 2026 09:54:11 +0800
Subject: [PATCH] feat: add index gc command for cleaning orphan nodes
---
internal/index/sqlite.go | 81 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 81 insertions(+), 0 deletions(-)
diff --git a/internal/index/sqlite.go b/internal/index/sqlite.go
index 6b7839a..db194fe 100644
--- a/internal/index/sqlite.go
+++ b/internal/index/sqlite.go
@@ -6,6 +6,7 @@
"fmt"
"os"
"path/filepath"
+ "strings"
_ "github.com/mattn/go-sqlite3"
"github.com/aisim/kb-cli/internal/graph"
@@ -177,3 +178,83 @@
return links, nil
}
+
+// NodeInfo 节点基本信息(用于 GC)
+type NodeInfo struct {
+ ID int64
+ Path string
+}
+
+// GetAllNodes 获取所有节点(用于 GC 检查)
+func (s *Store) GetAllNodes() ([]NodeInfo, error) {
+ rows, err := s.db.Query("SELECT id, path FROM nodes")
+ if err != nil {
+ return nil, fmt.Errorf("查询节点失败: %w", err)
+ }
+ defer rows.Close()
+
+ var nodes []NodeInfo
+ for rows.Next() {
+ var n NodeInfo
+ if err := rows.Scan(&n.ID, &n.Path); err != nil {
+ return nil, fmt.Errorf("扫描节点失败: %w", err)
+ }
+ nodes = append(nodes, n)
+ }
+
+ if err := rows.Err(); err != nil {
+ return nil, fmt.Errorf("遍历节点失败: %w", err)
+ }
+
+ return nodes, nil
+}
+
+// DeleteNodesByPaths 删除指定路径的节点及其关联边
+func (s *Store) DeleteNodesByPaths(paths []string) (int, error) {
+ if len(paths) == 0 {
+ return 0, nil
+ }
+
+ // 构建 IN 子句
+ placeholders := make([]string, len(paths))
+ args := make([]interface{}, len(paths))
+ for i, path := range paths {
+ placeholders[i] = "?"
+ args[i] = path
+ }
+
+ tx, err := s.db.Begin()
+ if err != nil {
+ return 0, fmt.Errorf("开始事务失败: %w", err)
+ }
+
+ // 先删除关联边
+ query := fmt.Sprintf(`
+ DELETE FROM edges
+ WHERE from_node IN (SELECT id FROM nodes WHERE path IN (%s))
+ OR to_node IN (SELECT id FROM nodes WHERE path IN (%s))
+ `, strings.Join(placeholders, ","), strings.Join(placeholders, ","))
+
+ // 参数需要重复两次
+ allArgs := append(args, args...)
+ _, err = tx.Exec(query, allArgs...)
+ if err != nil {
+ tx.Rollback()
+ return 0, fmt.Errorf("删除边失败: %w", err)
+ }
+
+ // 删除节点
+ query = fmt.Sprintf("DELETE FROM nodes WHERE path IN (%s)", strings.Join(placeholders, ","))
+ result, err := tx.Exec(query, args...)
+ if err != nil {
+ tx.Rollback()
+ return 0, fmt.Errorf("删除节点失败: %w", err)
+ }
+
+ if err := tx.Commit(); err != nil {
+ return 0, fmt.Errorf("提交事务失败: %w", err)
+ }
+
+ affected, _ := result.RowsAffected()
+ return int(affected), nil
+}
--
Gitblit v1.9.1