src/db — SQLite 層

Node 內建 node:sqlite + WAL + FTS5——無原生 build、無 wasm fallback
檔案:src/db/schema.sql · index.ts · queries.ts · sqlite-adapter.ts · wal-valve.ts

大方向

CodeGraph 用 Node 內建的 node:sqliteDatabaseSync)——真正的 SQLite,WAL + FTS5,穿一層 thin better-sqlite3 形狀的 adapter。bundle runtime 永遠帶 Node ≥22.5,所以 node:sqlite 一定可用:沒有原生 build step、沒有 wasm fallbackcodegraph status 會回報 live backend(node-sqlite,也是唯一 backend)。資料放 .codegraph/codegraph.db


1. Schema(schema.sql)

nodes / edges / files 表 schema.sql核心三表:符號、關係、檔案。

nodes 表欄位範例:id(PK)、kindnamequalified_namefile_pathlanguagestart_line/end_line/start_column/end_columndocstringsignaturevisibilityis_exported/is_async/is_static/is_abstractdecorators(JSON)、type_parameters(JSON)、return_typeupdated_at

edgessourcetargetkindmetadata(JSON)。另有 schema_versions 追蹤 migration。

教學重點:位置欄位(start/end line+column)讓「逐位元組對齊 on-disk 的原始碼」成為可能——explore 可以直接把符號的原始碼切出來。return_type 欄位是 receiver-type inference(C++ method return → 呼叫者型別推斷)的基礎。

2. DatabaseConnection / QueryBuilder

DatabaseConnection.initialize / open src/db/index.ts建庫 / 開庫,含 migration 與 FTS rebuild。

initialize 建 schema + 建 FTS 表 + 插 schema_versions;open 開既有庫並跑 migration。WAL 模式設定(journal_mode=WAL)在這裡——這就是「並行讀取永不阻塞在 writer」的來源。`isReplacedOnDisk()` 是 reopenIfReplaced(src/index.ts)偵測「.codegraph 被刪重建」用的。

QueryBuilder src/db/queries.ts全部 prepared statements——高階查詢的單一 SQL 來源。

所有底層 SQL(找節點、找邊、unresolved refs、metadata、FTS 查詢…)集中在此,用 prepared statements 快取。setProjectNameTokens(把專案名從搜尋 ranking 降權,因為它不是 symbol)也在這裡——對應 src/index.ts 的 wireLayers

3. WAL 管理

WalCheckpointValve src/db/wal-valve.ts背景被動 checkpoint,把 WAL 成長導向磁碟而不阻塞 writer。

indexAll/sync 大寫入時,把 autocheckpoint interval 設 0(關掉同步內建 checkpoint),改用 valve 在 worker thread 做 PASSIVE checkpoint——writer 永遠不卡。foldNow() 在「大量寫入後、主執行緒要讀之前」強制折疊(收尾)。這解決了 #1231 的病理:WAL 在 default 1000-page interval 下重寫熱頁,HDD 上 bulk index 從 19 分鐘變 45 秒。

4. FTS5 全文搜尋

nodes_fts schema.sql / bulk load依名稱瞬間找程式——FTS5 + 延遲重建。

FTS5 表讓 codegraph query / searchNodes 能依名稱/片段瞬間搜尋。indexAll 用 beginBulkNodeLoad()/endBulkNodeLoad():大量插入期間先丟掉 per-row FTS trigger,最後從 nodes 表重建一次——把插入成本從每行都同步改成一次重建。crash 在窗口內的下次 open 時自癒。

5. 本站實測對照

codegraph status(節錄)
Index Statistics:
  Files:     570
  Nodes:     12,733
  Edges:     44,903
  DB Size:   53.30 MB
  Backend:   node:sqlite — built-in (full WAL)
  Journal:   wal
看完這頁你應該能說出:node:sqlite 為何免 build、nodes/edges 表的關鍵欄位、WAL 延遲 checkpoint 的動機(#1231)、FTS 延遲重建的做法、以及 status 顯示 backend 的意義。