Skip to content

feat(db): SQLite foundation — connection, schema, repository, reindex, sync (T4) - #5

Merged
goofmint merged 3 commits into
mainfrom
feature/db-foundation
Jun 13, 2026
Merged

feat(db): SQLite foundation — connection, schema, repository, reindex, sync (T4)#5
goofmint merged 3 commits into
mainfrom
feature/db-foundation

Conversation

@goofmint

@goofmint goofmint commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Summary

SQLite データベース層の基盤を一通り実装し、T4.1〜T4.6 をカバー。

接続層 (T4.1)

  • openDatabase / closeDatabase.dennoh/ の自動作成、PRAGMA foreign_keys=ON
  • ジャーナルモードは SQLite デフォルト(DELETE)採用。WAL を採用しない理由は、将来のモバイルクライアントが同じ .db を直接開く前提で -wal / -shm サイドカーを発生させないため

スキーマ / マイグレーション (T4.2, T4.3)

  • MIGRATIONS: Record<number, Migration> 形式、runMigrations は冪等
  • v1 マイグレーション:
    • notes(id PK, path UNIQUE, created_at, updated_at, source, title, projects_json, tags_json)
    • notes_fts(FTS5, content=notes, unicode61 remove_diacritics 0
    • notesnotes_fts 同期トリガー(AFTER INSERT/UPDATE/DELETE)
      • SQLite の外部コンテンツ FTS5 は自動同期されないため、リポジトリ層が単純な SQL だけで FTS と整合するようトリガーで対応
  • schema_version テーブルで適用済みバージョンを記録
  • 将来のマイグレーション追加パターン(カラム追加 / インデックス / データ変換 / FTS 再構築)をコメント化

CRUD (T4.4)

  • insertNote / updateNote / deleteNote / getNoteById / getAllNotes
  • 全 mutation を db.transaction で包み、トリガーと同一 tx 内で FTS 同期
  • updateNote は対象行不在時に明示エラー
  • updated_at の更新は呼び出し側責任(disk 上 frontmatter とのレース回避のためリポジトリでは上書きしない)

Mapper

  • toNoteRow / fromNoteRowprojects / tags ⇔ JSON 列の双方向変換、title の null⇔undefined 変換、source のランタイム検証
  • body 引数は将来の FTS 本文インデックス用予約

Reindex (T4.5)

  • reindexAllDELETE FROM notes で全消し(トリガーが notes_fts を連動クリア)→ vault 再帰走査 → 各 .md を readNotetoNoteRowinsertNote
  • .dennoh/ を除外
  • 個別ファイルのエラーは errors[] に記録して継続

Startup diff sync (T4.6)

  • scanAndSync:FS スナップショット(path + mtime)と DB 行を突き合わせて add / update / delete を判定
  • mtime > Date.parse(updated_at) で UPDATE、Number.isNaN も UPDATE 扱い

CodeRabbit

公開 API (@/db)

  • 関数: openDatabase / closeDatabase / runMigrations / insertNote / updateNote / deleteNote / getNoteById / reindexAll / scanAndSync
  • 型: NoteRow / IndexStats / ReindexResult / SyncResult
  • 内部実装(mapper, getAllNotes, getCurrentVersion 等)は直接モジュール参照のみ可

設計上の限界

  • mtime と frontmatter updated_at は別の量。初回 reindex 直後の sync では mtime > updated_at が真になりやすく、変更がなくても UPDATE が走ることがある(無駄な再読込はあるがデータ損失はない)。完全 no-op 化したい場合は DB に mtime 列追加 + last-sync-mtime 比較への設計変更が必要。

Test plan

  • bun test(187 pass / 14 files / 352 expects)
  • bun run lint(Biome clean)
  • bun run typecheck(tsc --noEmit clean)
  • CodeRabbit のレビュー確認

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 新機能

    • ローカルSQLiteによるノート保存・接続管理、スキーマ移行とFTS検索インデックスを追加しました。
    • ノートの永続化用CRUD、ファイル→DBの再インデックス、ファイルシステムとDBの差分同期(追加・更新・削除)を導入しました。
    • ノートメタデータとDB行の相互変換ルールを整備しました。
  • テスト

    • 接続・マイグレーション・リポジトリ・再インデックス・同期の統合テストを追加しました。

…ndex, sync (T4)

Phase 1 — connection & migrations
- openDatabase / closeDatabase with auto .dennoh/ creation, foreign_keys ON,
  DELETE journal mode (no WAL — mobile clients open the .db directly so
  -wal/-shm sidecars are intentionally avoided)
- MIGRATIONS: Record<number, Migration> with idempotent runMigrations
- v1 creates notes + notes_fts (FTS5, content=notes, unicode61 tokenizer,
  remove_diacritics=0 for CJK / accented Latin)

Phase 2 — CRUD & FTS sync
- notes ↔ notes_fts sync triggers added to v1 migration (SQLite external-
  content FTS does NOT auto-sync; this is the documented trigger pattern)
- repository: insertNote / updateNote / deleteNote / getNoteById / getAllNotes,
  each mutation wrapped in db.transaction so trigger work shares the same tx
- mapper: toNoteRow / fromNoteRow with JSON column round-trip

Phase 3 — reindex & startup diff
- reindexAll: DELETE FROM notes (trigger clears FTS), recursive .md walk
  with .dennoh/ excluded, per-file errors recorded and execution continues
- scanAndSync: FS snapshot vs DB diff — INSERT new, UPDATE when
  mtime > updated_at, DELETE missing files
- index.ts trimmed to spec'd public API; internals reachable via direct
  module imports for tests

Covers T4.1–T4.6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

SQLite データベース層全体を実装し、ボルト内の Markdown ノートの永続化、スキーマ移行、CRUD 操作、ファイルシステム同期、一括再インデックスを提供します。

Changes

SQLite Database Layer

Layer / File(s) Summary
Types and database connection
src/db/types.ts, src/db/connection.ts, tests/db/connection.test.ts
NoteRow, NoteSearchResult, IndexStats 型を定義し、openDatabase がディレクトリを自動作成、index.db を初期化、外部キーを有効化し、closeDatabase が接続を切断します。
Schema versioning and migration system
src/db/schema.ts
schema_version テーブルで版管理を行い、migration 1 が notes テーブル、日本語/CJK 対応の notes_fts FTS5 仮想テーブル、および同期トリガを作成し、runMigrations が冪等的に適用します。
Domain to database mapping
src/db/mapper.ts
toNoteRowNoteMetadata から行を構築し、配列を JSON シリアライズして格納し、fromNoteRow がパースと型検証を行って NoteMetadata を復元します。
CRUD repository operations
src/db/repository.ts, tests/db/repository.test.ts
insertNote, updateNote, deleteNote, getNoteById, getAllNotes を実装し、トランザクション内で実行され、FTS トリガにより notes_fts と同期します。テストで CRUD 一連の整合性と FTS 同期を検証します。
Vault filesystem reindexing
src/db/reindex.ts, tests/db/reindex.test.ts
.dennoh/ を除外して再帰的に Markdown ファイルを走査し、既存行を削除してから全ファイルを読み込み・変換・挿入し、ファイル単位のエラーを収集して続行します。
Filesystem and database synchronization
src/db/sync.ts, tests/db/sync.test.ts
ファイルシステムをスナップショット取得し、DB 状態と比較して、新規は挿入、更新は updated_at と mtime で判定、削除は存在しないパスの行を削除し、操作ごとのエラーを蓄積します。
Database public API barrel
src/db/index.ts
全データベース関数・型を再エクスポートし、実装詳細とパブリック契約を文書化します。

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • goofmint/dennoh#3: Core domain types、constants、ファイル読み込み関数を提供し、本 PR のデータベース層がそれらを基盤として活用
  • goofmint/dennoh#1: src/db/index.ts のプレースホルダー(export {})を実装し、本 PR がそれを実 DB API バレルとして展開

Poem

🐰 ボルトを掘って見つけたメモの種、
SQLite に植えれば索引が芽吹く、
マイグレーションで根を整え、FTS で花咲く、
ファイルと DB をぴったり合わせるダンス、
うさぎは跳ねてテストに拍手する。

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed プルリクエストのタイトルは、SQLiteの基盤実装(接続、スキーマ、リポジトリ、再インデックス、同期)の主要な変更を明確に要約しており、変更セット全体の目的を適切に反映しています。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/db-foundation

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/db/reindex.ts`:
- Around line 19-32: In walkMdFiles (function walkMdFiles in src/db/reindex.ts
lines 19-32) add try/catch around the async fs.promises.readdir and around
recursive calls so any I/O error for a directory is caught, push an object
describing the failed path and error into a shared errors collection (or yield a
sentinel/error entry) and continue walking other entries instead of throwing; in
the sibling site (src/db/sync.ts lines 20-35) update walkMdFilesWithStats to
catch per-file readdir/stat errors (wrap fs.promises.readdir and
fs.promises.stat calls), accumulate failures into SyncResult.errors (use a
consistent error shape with path and error message), and ensure the function
continues processing remaining files so the aggregate sync flow does not abort
on single I/O failures.

In `@src/db/schema.ts`:
- Around line 96-103: The code currently only handles currentVersion <=
targetVersion; add a fail-fast check in runMigrations: after computing
targetVersion and currentVersion (from getCurrentVersion and MIGRATIONS), if
currentVersion > targetVersion throw a clear Error (or return a rejected
Promise) indicating the DB schema is newer than the binary and migration cannot
proceed; keep existing while loop for currentVersion < targetVersion unchanged.
Ensure the error message includes both currentVersion and targetVersion to aid
debugging.

In `@tests/db/connection.test.ts`:
- Around line 31-36: Wrap the test body that uses openDatabase and closeDatabase
in a try/finally to guarantee cleanup: call const db = openDatabase(vaultPath);
then use try { const row = db.query<{ answer: number }, []>("SELECT 1 AS
answer").get(); expect(row?.answer).toBe(1); } finally { closeDatabase(db); } so
closeDatabase(db) always runs even if the assertion or query throws.

In `@tests/db/reindex.test.ts`:
- Around line 52-57: Remove the conditional and iterate the two arrays as tuples
so the loop has no runtime guard: replace the for loop over indices that checks
idValue/dateValue with a tuple iteration that pairs elements from ids and dates
(e.g. const pairs = ids.map((id, i) => [id, dates[i]] as const); for (const
[idValue, dateValue] of pairs) { ... }), or alternatively use non‑null
assertions when indexing (const idValue = ids[i]!, const dateValue = dates[i]!)
inside the existing index loop and drop the if; target the variables ids, dates,
idValue and dateValue and remove the throw branch so the test contains no if.

In `@tests/db/sync.test.ts`:
- Around line 57-117: Add a new test case exercising the invalid updated_at and
errors-accumulation path: create two notes using generateId()/writeNote() — one
with a valid updatedAt (e.g. "2026-06-12T10:00:00+09:00") and one with an
invalid updatedAt string (e.g. "not-a-date") using fm({ updatedAt: ... }),
bumpMtime() on both files, then call scanAndSync(); assert that the valid note
is inserted/updated (using getNoteById() / notesCount()), the invalid note does
not increment added/updated, and that result.errors contains an entry for the
invalid file (and scanAndSync continues processing the other file). Also add a
separate small test that a single file with invalid updatedAt yields
result.errors length 1 and does not crash (verify DB unchanged) to cover the
Number.isNaN(updatedAtMs) branch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 24d90fcf-aa3d-43e6-a29f-4097ec323e82

📥 Commits

Reviewing files that changed from the base of the PR and between 8508d8e and 6598c25.

📒 Files selected for processing (12)
  • src/db/connection.ts
  • src/db/index.ts
  • src/db/mapper.ts
  • src/db/reindex.ts
  • src/db/repository.ts
  • src/db/schema.ts
  • src/db/sync.ts
  • src/db/types.ts
  • tests/db/connection.test.ts
  • tests/db/reindex.test.ts
  • tests/db/repository.test.ts
  • tests/db/sync.test.ts

Comment thread src/db/reindex.ts Outdated
Comment thread src/db/schema.ts
Comment thread tests/db/connection.test.ts
Comment thread tests/db/reindex.test.ts Outdated
Comment thread tests/db/sync.test.ts
Implemented from a Change Stack AI coding task.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
tests/db/reindex.test.ts (2)

26-29: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

row?.c ?? 0 は暗黙のフォールバックです。

COUNT(*) は常に行を返すため、rownull になることは想定外です。null の場合はエラーとして扱うべきです。

🛡️ 修正案
 function notesCount(db: Database): number {
   const row = db.query<{ c: number }, []>("SELECT COUNT(*) AS c FROM notes").get();
-  return row?.c ?? 0;
+  if (row === null) {
+    throw new Error("notesCount: unexpected null row from COUNT(*)");
+  }
+  return row.c;
 }

As per coding guidelines, src/**/*.ts の「フォールバック禁止: value || 'default' のような暗黙のフォールバックを指摘する」に該当します。ただし、これはテストコードなのでテスト失敗で問題が顕在化するため優先度は低いです。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/db/reindex.test.ts` around lines 26 - 29, The helper notesCount(db:
Database) currently uses an implicit fallback "row?.c ?? 0"; replace that with
explicit handling since COUNT(*) always returns a row: call db.query(...).get(),
check if the returned row is null/undefined and throw an Error (or assert) with
a clear message if so, otherwise return row.c; keep the function name notesCount
and the same query string to locate the change.

Source: Coding guidelines


46-99: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

エラー蓄積経路のテストが不足しています。

walkMdFiles の I/O エラー捕捉ロジック(Lines 27-33 in reindex.ts)と、個別ファイル処理エラーの蓄積(Lines 68-70 in reindex.ts)がテストされていません。例えば:

  1. 読み取り不可能なディレクトリを含む vault での reindexAll
  2. 不正な frontmatter を含む .md ファイルでの処理継続

これらのエッジケースをカバーするテストを追加することで、エラーハンドリングの堅牢性を検証できます。

As per coding guidelines, tests/**/*.ts の「エッジケース・エラー経路のカバレッジが十分か」を満たす必要があります。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/db/reindex.test.ts` around lines 46 - 99, Add tests to exercises
reindexAll's error-accumulation paths: (1) create a vault subdirectory with
permissions that cause walkMdFiles to throw (use fs.chmodSync to remove
read/execute before calling reindexAll and restore after) and assert the
returned result.errors contains the I/O error and result.processed is 0; (2) add
a test that writes one valid note (via writeNote) and one .md with deliberately
broken frontmatter/invalid contents so parsing fails, call reindexAll and assert
result.processed counts only the valid file, result.errors includes the per-file
parse error, and notesCount(db) reflects only successfully indexed rows;
reference the reindexAll and walkMdFiles behaviors when locating code to
exercise.

Source: Coding guidelines

tests/db/sync.test.ts (1)

29-32: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

row?.c ?? 0 は暗黙のフォールバックです。

tests/db/reindex.test.ts と同じパターンです。COUNT(*) は常に行を返すため、null の場合は想定外のエラーとして扱うべきです。

🛡️ 修正案
 function notesCount(db: Database): number {
   const row = db.query<{ c: number }, []>("SELECT COUNT(*) AS c FROM notes").get();
-  return row?.c ?? 0;
+  if (row === null) {
+    throw new Error("notesCount: unexpected null row from COUNT(*)");
+  }
+  return row.c;
 }

As per coding guidelines, フォールバック禁止に該当しますが、テストコードなので優先度は低いです。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/db/sync.test.ts` around lines 29 - 32, The helper notesCount(db:
Database) currently uses an implicit fallback "row?.c ?? 0"; change it to treat
a missing row as an unexpected error: after the query in notesCount, check if
row is null/undefined and throw a clear Error (e.g. "COUNT(*) returned no row in
notesCount") instead of returning 0, otherwise return row.c; update the
notesCount function body accordingly so the test fails loudly on unexpected DB
behavior (this mirrors the same fix needed for the similar pattern in
tests/db/reindex.test.ts).

Source: Coding guidelines

src/db/sync.ts (1)

64-71: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

errors が宣言前に使用されており、TDZ (Temporal Dead Zone) によりランタイムエラーが発生します。

Line 64 で walkMdFilesWithStats(vaultPath, errors) を呼び出していますが、errors は Line 71 で宣言されています。JavaScript/TypeScript の const/let は宣言前にアクセスすると ReferenceError をスローします。

🐛 修正案
 export async function scanAndSync(db: Database, vaultPath: string): Promise<SyncResult> {
   // Pull the FS view first so we have a stable snapshot before touching the
   // DB; reading both then diffing minimizes the time window where external
   // writes during scan could be missed.
+  const errors: SyncResult["errors"] = [];
   const fsFiles = new Map<string, number>();
   for await (const file of walkMdFilesWithStats(vaultPath, errors)) {
     fsFiles.set(file.path, file.mtimeMs);
   }

   const dbRows = getAllNotes(db);
   const dbByPath = new Map(dbRows.map((r) => [r.path, r]));

-  const errors: SyncResult["errors"] = [];
   let added = 0;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/db/sync.ts` around lines 64 - 71, The code calls
walkMdFilesWithStats(vaultPath, errors) before errors is declared, causing a TDZ
ReferenceError; fix this by declaring and initializing errors (const errors:
SyncResult["errors"] = []) before the for-await loop (i.e., move the errors
declaration above the call to walkMdFilesWithStats), then keep passing that
errors array into walkMdFilesWithStats and downstream logic (fsFiles population,
getAllNotes/dbByPath) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/db/reindex.ts`:
- Around line 40-45: Remove the unnecessary try/catch wrappers around the
recursive asynchronous generator yield* calls: in src/db/reindex.ts (lines
40-45) delete the try { yield* walkMdFiles(full, errors); } catch (...) block
and replace it with a plain yield* walkMdFiles(full, errors); call (no other
changes needed there because errors[] is handled by the callee); likewise in
src/db/sync.ts (lines 41-46) remove the try/catch around yield*
walkMdFilesWithStats(full, errors, statsMap); and use a direct yield*
walkMdFilesWithStats(full, errors, statsMap); call, leaving error collection to
the existing inner logic.

---

Outside diff comments:
In `@src/db/sync.ts`:
- Around line 64-71: The code calls walkMdFilesWithStats(vaultPath, errors)
before errors is declared, causing a TDZ ReferenceError; fix this by declaring
and initializing errors (const errors: SyncResult["errors"] = []) before the
for-await loop (i.e., move the errors declaration above the call to
walkMdFilesWithStats), then keep passing that errors array into
walkMdFilesWithStats and downstream logic (fsFiles population,
getAllNotes/dbByPath) unchanged.

In `@tests/db/reindex.test.ts`:
- Around line 26-29: The helper notesCount(db: Database) currently uses an
implicit fallback "row?.c ?? 0"; replace that with explicit handling since
COUNT(*) always returns a row: call db.query(...).get(), check if the returned
row is null/undefined and throw an Error (or assert) with a clear message if so,
otherwise return row.c; keep the function name notesCount and the same query
string to locate the change.
- Around line 46-99: Add tests to exercises reindexAll's error-accumulation
paths: (1) create a vault subdirectory with permissions that cause walkMdFiles
to throw (use fs.chmodSync to remove read/execute before calling reindexAll and
restore after) and assert the returned result.errors contains the I/O error and
result.processed is 0; (2) add a test that writes one valid note (via writeNote)
and one .md with deliberately broken frontmatter/invalid contents so parsing
fails, call reindexAll and assert result.processed counts only the valid file,
result.errors includes the per-file parse error, and notesCount(db) reflects
only successfully indexed rows; reference the reindexAll and walkMdFiles
behaviors when locating code to exercise.

In `@tests/db/sync.test.ts`:
- Around line 29-32: The helper notesCount(db: Database) currently uses an
implicit fallback "row?.c ?? 0"; change it to treat a missing row as an
unexpected error: after the query in notesCount, check if row is null/undefined
and throw a clear Error (e.g. "COUNT(*) returned no row in notesCount") instead
of returning 0, otherwise return row.c; update the notesCount function body
accordingly so the test fails loudly on unexpected DB behavior (this mirrors the
same fix needed for the similar pattern in tests/db/reindex.test.ts).
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 10d7ceba-7ff5-403e-b10b-1fe1a5697f68

📥 Commits

Reviewing files that changed from the base of the PR and between 6598c25 and a91f7ff.

📒 Files selected for processing (6)
  • src/db/reindex.ts
  • src/db/schema.ts
  • src/db/sync.ts
  • tests/db/connection.test.ts
  • tests/db/reindex.test.ts
  • tests/db/sync.test.ts

Comment thread src/db/reindex.ts Outdated
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 2 file(s) based on 1 unresolved review comment.

Files modified:

  • src/db/reindex.ts
  • src/db/sync.ts

Commit: 22032555abe961b3ee6692ff311629b25a589e15

The changes have been pushed to the feature/db-foundation branch.

Time taken: 1m 34s

Fixed 2 file(s) based on 1 unresolved review comment.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/db/sync.ts (1)

54-69: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

errors 変数が宣言前に参照されており、実行時に ReferenceError が発生します。

Line 59 で walkMdFilesWithStats(vaultPath, errors) を呼び出していますが、errors は Line 66 で宣言されています。これは Temporal Dead Zone (TDZ) エラーであり、scanAndSync を呼び出すと即座にクラッシュします。

errors 配列の宣言を for await ループの前に移動してください。

🐛 修正案
 export async function scanAndSync(db: Database, vaultPath: string): Promise<SyncResult> {
   // Pull the FS view first so we have a stable snapshot before touching the
   // DB; reading both then diffing minimizes the time window where external
   // writes during scan could be missed.
+  const errors: SyncResult["errors"] = [];
   const fsFiles = new Map<string, number>();
   for await (const file of walkMdFilesWithStats(vaultPath, errors)) {
     fsFiles.set(file.path, file.mtimeMs);
   }

   const dbRows = getAllNotes(db);
   const dbByPath = new Map(dbRows.map((r) => [r.path, r]));

-  const errors: SyncResult["errors"] = [];
   let added = 0;
   let updated = 0;
   let deleted = 0;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/db/sync.ts` around lines 54 - 69, In scanAndSync move the
declaration/initialization of the errors array before it's first used: declare
"const errors: SyncResult['errors'] = [];" above the for-await loop so the call
to walkMdFilesWithStats(vaultPath, errors) uses a valid array; this keeps the
rest of the function (variables added/updated/deleted and dbRows/dbByPath logic)
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/db/sync.ts`:
- Around line 54-69: In scanAndSync move the declaration/initialization of the
errors array before it's first used: declare "const errors: SyncResult['errors']
= [];" above the for-await loop so the call to walkMdFilesWithStats(vaultPath,
errors) uses a valid array; this keeps the rest of the function (variables
added/updated/deleted and dbRows/dbByPath logic) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4b42a66d-f5a2-48a9-a34b-96e551775de8

📥 Commits

Reviewing files that changed from the base of the PR and between a91f7ff and 2203255.

📒 Files selected for processing (2)
  • src/db/reindex.ts
  • src/db/sync.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant