Skip to content

Commit 28f6e90

Browse files
authored
fix(cli): accept -d/--db on build to match every other DB-scoped command (#1183)
Build silently wrote to `<dir>/.codegraph/graph.db` with no way to override while stats/query/where/watch all honor --db. The asymmetry blocked dogfooding workflows that need an isolated DB and surprised users who expected the flag to work everywhere. Wire opts.db through BuildGraphOpts.dbPath; setupPipeline resolves it absolute and falls back to the previous default. Mirrors watch's pattern (#987). Closes #1177.
1 parent 16840aa commit 28f6e90

4 files changed

Lines changed: 53 additions & 1 deletion

File tree

src/cli/commands/build.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const command: CommandDefinition = {
77
name: 'build [dir]',
88
description: 'Parse repo and build graph in .codegraph/graph.db',
99
options: [
10+
['-d, --db <path>', 'Path to graph.db (default: <dir>/.codegraph/graph.db)'],
1011
['--no-incremental', 'Force full rebuild (ignore file hashes)'],
1112
['--no-ast', 'Skip AST node extraction (calls, new, string, regex, throw, await)'],
1213
['--no-complexity', 'Skip complexity metrics computation'],
@@ -23,6 +24,7 @@ export const command: CommandDefinition = {
2324
engine: engine as EngineMode,
2425
dataflow: opts.dataflow as boolean,
2526
cfg: opts.cfg as boolean,
27+
dbPath: opts.db ? path.resolve(opts.db as string) : undefined,
2628
});
2729
},
2830
};

src/domain/graph/builder/pipeline.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,9 @@ function loadAliases(ctx: PipelineContext): void {
167167

168168
function setupPipeline(ctx: PipelineContext): void {
169169
ctx.rootDir = path.resolve(ctx.rootDir);
170-
ctx.dbPath = path.join(ctx.rootDir, '.codegraph', 'graph.db');
170+
ctx.dbPath = ctx.opts.dbPath
171+
? path.resolve(ctx.opts.dbPath)
172+
: path.join(ctx.rootDir, '.codegraph', 'graph.db');
171173

172174
// Detect whether native engine is available.
173175
const enginePref = ctx.opts.engine || 'auto';

src/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,12 @@ export interface BuildGraphOpts {
10721072
*/
10731073
exclude?: string[];
10741074
skipRegistry?: boolean;
1075+
/**
1076+
* Override the graph.db location. Resolved absolute. When omitted, the
1077+
* pipeline writes to `<rootDir>/.codegraph/graph.db` — same default as
1078+
* `findDbPath` for every other DB-scoped command.
1079+
*/
1080+
dbPath?: string;
10751081
}
10761082

10771083
/** Build timing result from buildGraph. */

tests/integration/build.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,48 @@ describe('buildGraph', () => {
153153
});
154154
});
155155

156+
describe('buildGraph with custom dbPath (issue #1177)', () => {
157+
let customDir: string, customDbPath: string;
158+
159+
beforeAll(async () => {
160+
customDir = fs.mkdtempSync(path.join(os.tmpdir(), 'codegraph-custom-db-'));
161+
for (const [name, content] of Object.entries(FIXTURE_FILES)) {
162+
fs.writeFileSync(path.join(customDir, name), content);
163+
}
164+
customDbPath = path.join(os.tmpdir(), `codegraph-custom-${Date.now()}.db`);
165+
await buildGraph(customDir, { skipRegistry: true, dbPath: customDbPath });
166+
});
167+
168+
afterAll(() => {
169+
if (customDir) fs.rmSync(customDir, { recursive: true, force: true });
170+
if (customDbPath && fs.existsSync(customDbPath)) {
171+
fs.rmSync(customDbPath, { force: true });
172+
// Clean up sidecar WAL/SHM files
173+
for (const ext of ['-wal', '-shm', '.lock']) {
174+
const sidecar = `${customDbPath}${ext}`;
175+
if (fs.existsSync(sidecar)) fs.rmSync(sidecar, { force: true });
176+
}
177+
}
178+
});
179+
180+
test('writes DB to the custom path, not <rootDir>/.codegraph/graph.db', () => {
181+
expect(fs.existsSync(customDbPath)).toBe(true);
182+
expect(fs.existsSync(path.join(customDir, '.codegraph', 'graph.db'))).toBe(false);
183+
});
184+
185+
test('custom DB contains expected nodes and edges', () => {
186+
const db = new Database(customDbPath, { readonly: true });
187+
const files = db
188+
.prepare("SELECT file FROM nodes WHERE kind = 'file'")
189+
.all()
190+
.map((r) => r.file);
191+
db.close();
192+
expect(files).toContain('math.js');
193+
expect(files).toContain('utils.js');
194+
expect(files).toContain('index.js');
195+
});
196+
});
197+
156198
describe('three-tier incremental builds', () => {
157199
let incrDir: string, incrDbPath: string;
158200

0 commit comments

Comments
 (0)