From 09c2a03cefa687832257d3b816da50db3cfcc0f2 Mon Sep 17 00:00:00 2001
From: ai_xiaopei <xiaopei@aisim.cn>
Date: Sat, 25 Jul 2026 23:48:11 +0800
Subject: [PATCH] feat: 实现输出格式化

---
 internal/index/sqlite.go |  149 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 149 insertions(+), 0 deletions(-)

diff --git a/internal/index/sqlite.go b/internal/index/sqlite.go
new file mode 100644
index 0000000..e1086df
--- /dev/null
+++ b/internal/index/sqlite.go
@@ -0,0 +1,149 @@
+package index
+
+import (
+	"database/sql"
+	"encoding/json"
+	"fmt"
+	"os"
+	"path/filepath"
+
+	_ "github.com/mattn/go-sqlite3"
+	"github.com/aisim/kb-cli/internal/graph"
+)
+
+// Store SQLite 存储层
+type Store struct {
+	db *sql.DB
+}
+
+// Open 打开或创建数据库
+func Open(dbPath string) (*Store, error) {
+	// 确保目录存在
+	dir := filepath.Dir(dbPath)
+	if err := os.MkdirAll(dir, 0755); err != nil {
+		return nil, fmt.Errorf("创建目录失败: %w", err)
+	}
+
+	db, err := sql.Open("sqlite3", dbPath+"?_journal_mode=WAL")
+	if err != nil {
+		return nil, fmt.Errorf("打开数据库失败: %w", err)
+	}
+
+	s := &Store{db: db}
+	if err := s.initTables(); err != nil {
+		db.Close()
+		return nil, err
+	}
+	return s, nil
+}
+
+// Close 关闭数据库
+func (s *Store) Close() error {
+	return s.db.Close()
+}
+
+// initTables 创建表结构
+func (s *Store) initTables() error {
+	schema := `
+	CREATE TABLE IF NOT EXISTS meta (
+		key   TEXT PRIMARY KEY,
+		value TEXT NOT NULL
+	);
+
+	CREATE TABLE IF NOT EXISTS nodes (
+		id          INTEGER PRIMARY KEY AUTOINCREMENT,
+		path        TEXT NOT NULL UNIQUE,
+		title       TEXT,
+		section     TEXT,
+		tags        TEXT,
+		entities    TEXT,
+		wikilinks   TEXT,
+		content_fts TEXT,
+		created_at  TEXT DEFAULT (datetime('now')),
+		updated_at  TEXT DEFAULT (datetime('now'))
+	);
+
+	CREATE TABLE IF NOT EXISTS edges (
+		id          INTEGER PRIMARY KEY AUTOINCREMENT,
+		from_node   INTEGER NOT NULL,
+		to_node     INTEGER NOT NULL,
+		relation    TEXT NOT NULL,
+		label       TEXT,
+		UNIQUE(from_node, to_node, relation, label)
+	);
+
+	CREATE INDEX IF NOT EXISTS idx_nodes_section ON nodes(section);
+	CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_node);
+	CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_node);
+	CREATE INDEX IF NOT EXISTS idx_edges_label ON edges(label);
+	`
+	_, err := s.db.Exec(schema)
+	if err != nil {
+		return fmt.Errorf("创建表失败: %w", err)
+	}
+	return nil
+}
+
+// ClearData 清空数据(重建前调用)
+func (s *Store) ClearData() error {
+	_, err := s.db.Exec("DELETE FROM edges; DELETE FROM nodes;")
+	return err
+}
+
+// InsertNode 插入节点
+func (s *Store) InsertNode(n *graph.Node) (int64, error) {
+	tagsJSON, _ := json.Marshal(n.Tags)
+	entitiesJSON, _ := json.Marshal(n.Entities)
+	wikilinksJSON, _ := json.Marshal(n.Wikilinks)
+
+	result, err := s.db.Exec(`
+		INSERT INTO nodes (path, title, section, tags, entities, wikilinks, content_fts)
+		VALUES (?, ?, ?, ?, ?, ?, ?)
+	`, n.Path, n.Title, n.Section, string(tagsJSON), string(entitiesJSON),
+		string(wikilinksJSON), n.Content)
+	if err != nil {
+		return 0, err
+	}
+	return result.LastInsertId()
+}
+
+// InsertEdge 插入边
+func (s *Store) InsertEdge(e *graph.Edge) error {
+	_, err := s.db.Exec(`
+		INSERT OR IGNORE INTO edges (from_node, to_node, relation, label)
+		VALUES (?, ?, ?, ?)
+	`, e.FromNode, e.ToNode, e.Relation, e.Label)
+	return err
+}
+
+// SetMeta 设置元信息
+func (s *Store) SetMeta(key, value string) error {
+	_, err := s.db.Exec(`
+		INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)
+	`, key, value)
+	return err
+}
+
+// GetMeta 获取元信息
+func (s *Store) GetMeta(key string) (string, error) {
+	var value string
+	err := s.db.QueryRow("SELECT value FROM meta WHERE key = ?", key).Scan(&value)
+	if err == sql.ErrNoRows {
+		return "", nil
+	}
+	return value, err
+}
+
+// NodeCount 返回节点数量
+func (s *Store) NodeCount() (int, error) {
+	var count int
+	err := s.db.QueryRow("SELECT COUNT(*) FROM nodes").Scan(&count)
+	return count, err
+}
+
+// EdgeCount 返回边数量
+func (s *Store) EdgeCount() (int, error) {
+	var count int
+	err := s.db.QueryRow("SELECT COUNT(*) FROM edges").Scan(&count)
+	return count, err
+}

--
Gitblit v1.9.1