feat(config): restore path aliases with TS 6.x-compatible subpath imports#672
feat(config): restore path aliases with TS 6.x-compatible subpath imports#672carlos-alm merged 6 commits intomainfrom
Conversation
Add queryAll/queryGet methods to NativeDatabase for parameterized SELECT execution via rusqlite, returning rows as serde_json::Value objects. This enables NodeQuery and arbitrary SQL to dispatch through the native engine without porting the SQL builder to Rust. - NativeDatabase: queryAll, queryGet, validateSchemaVersion methods - NodeQuery: all()/get() accept optional nativeDb for native dispatch - connection.ts: closeDbPair/closeDbPairDeferred lifecycle helpers - finalize.ts/pipeline.ts: use unified close helpers - detect-changes.ts, build-structure.ts: 3 starter straggler migrations - Comprehensive db.prepare() audit (194 calls, tiered migration plan) - 42 new tests (parity, query execution, version check; skip-guarded)
|
Claude finished @carlos-alm's task —— View job Reviewing PR: Generic Query Execution on NativeDatabaseConducting comprehensive 5-phase review of this performance improvement PR. Todo List
Root Cause AnalysisProblem Being Solved: This PR addresses performance bottlenecks in the dual-engine architecture by adding generic query execution capabilities to the native Rust backend. Currently, JavaScript builds SQL queries but executes them through the slower Why This Approach: The PR enables the existing Risk Assessment: Low risk - purely additive functionality with comprehensive test coverage and fallback to existing behavior when native DB is unavailable. Configuration Change Detection✅ No high-risk configuration changes detected. The PR:
Test Integrity✅ Strong test coverage with proper safeguards:
The test quality is excellent with proper isolation, comprehensive edge case coverage, and rigorous parity validation. Code QualityRust Implementation (
TypeScript Integration (
Connection Management (
Critical Architecture Compliance:
Backlog ComplianceZero-dep: ✅ - No new runtime dependencies added, builds on existing rusqlite foundation Foundation-aligned: ✅ - Fully compliant with all principles:
Problem-fit: 4/5 - Directly addresses AI token waste and improves query performance for large codebases. While not solving the core "lost AI" navigation problem directly, faster queries enable more responsive AI assistance and reduce round-trip latency. Breaking: No - Purely additive with backward-compatible optional parameters Tier: 1 (zero-dep ✓ + foundation-aligned ✓) Critical ConcernsMinor Issues:
Strengths:
Final Recommendation
Conditions for approval:
|
Greptile SummaryThis PR does two things under one commit: (1) migrates path aliases from Key changes:
Note: The PR title and description focus entirely on path aliases, but the Phase 6.16 NativeDatabase work is the larger portion of the diff. Future PRs may benefit from separating infrastructure changes from configuration changes to simplify review scope. Confidence Score: 5/5Safe to merge — no P0/P1 issues found; all remaining findings are P2 style suggestions. The prior regression in detect-changes.ts (hasTable semantics) is correctly fixed. The Rust query methods are well-tested with a combinatorial parity suite. Connection lifecycle ordering is correctly enforced. The subpath imports setup is validated by npx tsc --noEmit, the full test suite (2128 pass), and verify-imports. All open findings are P2: a minor null-safety note on a COUNT(*) cast that can never fail in practice, a silent cell-error mapping in Rust, and a future-proofing note about the #types exact pattern. No files require special attention. crates/codegraph-core/src/native_db.rs and src/domain/graph/builder/stages/build-structure.ts have the minor P2 observations noted above. Important Files Changed
Sequence DiagramsequenceDiagram
participant Caller as Pipeline Stage
participant NQ as NodeQuery
participant Native as NativeDatabase (Rust/NAPI)
participant SQLite as better-sqlite3
Caller->>NQ: .all(db, nativeDb?) / .get(db, nativeDb?)
NQ->>NQ: build() → { sql, params }
alt nativeDb available
NQ->>NQ: validateNativeParams(params)
NQ->>Native: queryAll(sql, params) / queryGet(sql, params)
Native->>Native: json_to_rusqlite_params()
Native->>Native: stmt.query_map() / query_rows.next()
Native->>Native: row_to_json() per row
Native-->>NQ: Vec<serde_json::Value> / Option<Value>
NQ-->>Caller: TRow[] / TRow | undefined
else JS fallback
NQ->>SQLite: db.prepare(sql).all(...params)
SQLite-->>NQ: TRow[]
NQ-->>Caller: TRow[]
end
note over Caller,SQLite: closeDbPair() ensures NativeDatabase.close() before better-sqlite3.close() (WAL checkpoint ordering)
Reviews (2): Last reviewed commit: "Merge remote-tracking branch 'origin/fea..." | Re-trigger Greptile |
| let hasTable = false; | ||
| try { | ||
| db.prepare('SELECT 1 FROM file_hashes LIMIT 1').get(); | ||
| hasTable = true; | ||
| const probe = nativeDb | ||
| ? nativeDb.queryGet('SELECT 1 FROM file_hashes LIMIT 1', []) | ||
| : db.prepare('SELECT 1 FROM file_hashes LIMIT 1').get(); | ||
| if (probe) hasTable = true; | ||
| } catch { | ||
| /* table doesn't exist */ |
There was a problem hiding this comment.
hasTable probe semantics changed for JS fallback path
The old JS-only code set hasTable = true if the prepare/get call didn't throw — regardless of whether any rows were returned:
// Old:
db.prepare('SELECT 1 FROM file_hashes LIMIT 1').get();
hasTable = true;The new code adds an existence check (if (probe)), so an empty file_hashes table now sets hasTable = false on both the native and the JS fallback paths:
const probe = nativeDb
? nativeDb.queryGet(...)
: db.prepare('SELECT 1 FROM file_hashes LIMIT 1').get();
if (probe) hasTable = true; // returns undefined for empty table on JS pathIn practice this makes the two paths behave consistently and triggers isFullBuild: true for an empty hash table, which is arguably more correct. However the JS fallback path now has different semantics than the JS-only code it replaced, which could be surprising to anyone relying on the old "table exists = incremental" contract. A brief comment noting the intentional behaviour change would prevent future confusion.
There was a problem hiding this comment.
Fixed -- this was actually a regression, not an intentional behavior change. The old JS-only code set hasTable = true unconditionally when the query succeeded (table exists), regardless of row count. The new code added if (probe) which broke the empty-table case, causing isFullBuild: true instead of incremental.
Restored the original semantics: the try/catch now runs the probe query for its side-effect (throw if table missing), and sets hasTable = true unconditionally on success. Both the nativeDb and JS fallback paths now correctly treat an existing-but-empty file_hashes table as incremental (not full build). This was the CI failure root cause.
…orts Replace deprecated baseUrl/paths with Node.js subpath imports (package.json imports field) + customConditions in tsconfig.json. Uses @codegraph/source condition for compile-time resolution to src/, default condition for runtime resolution to dist/. - Add imports field with conditional mappings for all 11 src/ subdirectories + #types - Add customConditions: ["@codegraph/source"] to tsconfig.json - Add resolve.conditions to vitest.config.ts for Vite resolver - Update verify-imports.ts to resolve #-prefixed specifiers - Migrate 3 deeply nested files as proof-of-concept Closes #668
#672) The nativeDb migration changed the file_hashes probe from unconditionally setting hasTable=true on successful query to only setting it when the query returns a row. This caused an empty file_hashes table (exists but no rows) to be treated as a full build instead of incremental, breaking the detect-changes test.
- Document row_to_json BLOB/error-to-null contract in Rust doc comment - Clarify queryAll/queryGet doc comments re: SELECT-only intent - Add validateNativeParams runtime check before dispatching to nativeDb
|
Addressed all Greptile findings:
|
|
Addressed Claude review conditions:
Additionally addressed the Greptile findings with doc comments, runtime param validation, and the hasTable fix. See the comment above for details. |
|
Claude finished @carlos-alm's task —— View job Acknowledging Review Feedback ImplementationThank you for the thorough updates addressing both the Claude and Greptile review feedback! Todo List
Summary of Changes AddressedGreptile Findings Addressed:
Claude Review Conditions:
Key Improvements MadeThe fix to the The addition of Great work addressing all the review feedback comprehensively while maintaining the PR's core functionality and performance improvements! |
Summary
baseUrl/pathswith Node.js subpath imports (package.jsonimportsfield) +customConditionsintsconfig.json@codegraph/sourcecondition for compile-time resolution tosrc/,defaultcondition for runtime resolution todist/Details
How it works:
Changes:
package.json—importsfield with conditional mappings for all 11src/subdirectories +#typestsconfig.json—customConditions: ["@codegraph/source"]vitest.config.ts—resolve.conditions: ['@codegraph/source']for Vite resolverscripts/verify-imports.ts— resolves#-prefixed specifiers through the imports mapbuild-structure.ts,build-edges.ts,collect-files.ts)Test plan
npx tsc --noEmit— zero errorsnpm run build—#specifiers preserved in compiled JSnode dist/cli.js --help— runtime resolves viadefaultconditionnpm run verify-imports— 281 files passnpm test— 2128 pass (1 pre-existing failure unrelated to this PR)biome check— clean on migrated filesCloses #668