Skip to content

feat(stores): add sqlc typed SQL to whisper and codedb stores#346

Merged
rsnodgrass merged 4 commits intomainfrom
ryan/sqlc-typed-sql
Mar 29, 2026
Merged

feat(stores): add sqlc typed SQL to whisper and codedb stores#346
rsnodgrass merged 4 commits intomainfrom
ryan/sqlc-typed-sql

Conversation

@rsnodgrass
Copy link
Copy Markdown
Contributor

@rsnodgrass rsnodgrass commented Mar 29, 2026

Summary

Adds sqlc strongly-typed SQL code generation to both SQLite stores, replacing hand-written database/sql query/scan code with compile-time-checked generated Go code.

  • Whisper store: All 13 static queries (insert, cursor CRUD, relay tracking, pruning) now use sqlc-generated types. Schema consolidated via //go:embed so one .sql file serves both sqlc generation and runtime DDL. Dynamic queries (GetWhispers, GetWhispersPage) kept as hand-written SQL.
  • CodeDB store: 32 static queries across 7 domain files (repos, commits, blobs, file_revs, diffs, refs, github) now use sqlc-generated types. Transaction pattern uses codedbsqlc.New(tx) for typed inserts within existing indexState.tx. Dynamic search SQL and ParseSymbols IN-clause queries kept hand-written.
  • Nullable handling: Replaced *string/*int64 pointer patterns with sql.NullString/sql.NullInt64 throughout, matching sqlc conventions.
graph LR
    subgraph "sqlc pipeline"
        S[schema.sql] --> G[sqlc generate]
        Q[queries.sql] --> G
        G --> C[db.go + models.go + queries.sql.go]
    end
    subgraph "runtime"
        S -->|go:embed| R[CreateSchema]
        C --> W[Store.queries]
    end
Loading

Test plan

  • go build ./internal/codedb/... ./internal/whisper/... — clean
  • go test ./internal/whisper/store/... — all pass
  • go test ./internal/codedb/... — all pass (9 sub-packages)
  • make lint — 0 issues

Co-authored-by: SageOx ox@sageox.ai

Summary by CodeRabbit

  • Chores

    • Switched to generated, context-aware database helpers with nullable-aware types; added canonical DB schemas and integrated typed query constructors for more robust, transactional storage.
    • Replaced ad-hoc SQL with idempotent upserts and lookups, improving persistence consistency and blob/commit/ref handling.
  • Tests

    • Updated unit tests to assert nullable semantics for timestamps, optional strings/ints, and file-mtime persistence.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 04c9f224-74f8-4d53-ad5b-b5d8372e48c3

📥 Commits

Reviewing files that changed from the base of the PR and between 8924458 and c0caa2e.

📒 Files selected for processing (34)
  • internal/codedb/index/github.go
  • internal/codedb/index/helpers_test.go
  • internal/codedb/index/indexer.go
  • internal/codedb/index/indexer_coverage_test.go
  • internal/codedb/index/perf_regression_test.go
  • internal/codedb/sqlc/blobs.sql.go
  • internal/codedb/sqlc/commits.sql.go
  • internal/codedb/sqlc/db.go
  • internal/codedb/sqlc/diffs.sql.go
  • internal/codedb/sqlc/file_revs.sql.go
  • internal/codedb/sqlc/github.sql.go
  • internal/codedb/sqlc/models.go
  • internal/codedb/sqlc/queries/blobs.sql
  • internal/codedb/sqlc/queries/commits.sql
  • internal/codedb/sqlc/queries/diffs.sql
  • internal/codedb/sqlc/queries/file_revs.sql
  • internal/codedb/sqlc/queries/github.sql
  • internal/codedb/sqlc/queries/refs.sql
  • internal/codedb/sqlc/queries/repos.sql
  • internal/codedb/sqlc/queries/symbols.sql
  • internal/codedb/sqlc/refs.sql.go
  • internal/codedb/sqlc/repos.sql.go
  • internal/codedb/sqlc/schema.sql
  • internal/codedb/sqlc/symbols.sql.go
  • internal/codedb/store/store.go
  • internal/whisper/store/schema.go
  • internal/whisper/store/sqlc/db.go
  • internal/whisper/store/sqlc/models.go
  • internal/whisper/store/sqlc/queries.sql
  • internal/whisper/store/sqlc/queries.sql.go
  • internal/whisper/store/sqlc/schema.sql
  • internal/whisper/store/store.go
  • internal/whisper/store/store_coverage_test.go
  • sqlc.yaml

📝 Walkthrough

Walkthrough

Replaces ad-hoc SQL with sqlc-generated, context-aware query methods across CodeDB and Whisper; threads context through indexing and store flows; converts nullable handling to database/sql null types; adds sqlc schemas/models/queries; and exposes typed Queries via Store wrappers.

Changes

Cohort / File(s) Summary
CodeDB sqlc core & schema
internal/codedb/sqlc/schema.sql, internal/codedb/sqlc/models.go, internal/codedb/sqlc/db.go
Add CodeDB SQLite schema, generated models, DBTX interface, and Queries constructor/WithTx.
CodeDB sqlc queries & methods
internal/codedb/sqlc/queries/*.sql, internal/codedb/sqlc/*.sql.go
Add sqlc query definitions and generated implementations for repos, commits, refs, blobs, diffs, file_revs, symbols, and GitHub-related tables (PRs/issues/comments/file mtimes).
CodeDB indexer & GitHub indexing
internal/codedb/index/github.go, internal/codedb/index/indexer.go
Thread ctx through indexing, replace raw SQL with sqlc calls, use codedbsqlc.New(tx) in transactions, and switch nullable conversions to sql.Null* helpers and sqlc param structs.
CodeDB store & tests
internal/codedb/store/store.go, internal/codedb/index/helpers_test.go, internal/codedb/index/indexer_coverage_test.go, internal/codedb/index/perf_regression_test.go
Store now holds prebound *codedbsqlc.Queries, add accessor and QueriesFromTx; update tests to pass context.Context and assert sql.Null* semantics.
Whisper sqlc core & schema
internal/whisper/store/sqlc/schema.sql, internal/whisper/store/sqlc/models.go, internal/whisper/store/sqlc/db.go
Add Whisper SQLite schema, generated models, DBTX interface, and Queries constructor/WithTx for whisper store.
Whisper sqlc queries & methods
internal/whisper/store/sqlc/queries.sql, internal/whisper/store/sqlc/queries.sql.go
Add sqlc query definitions and generated methods for whispers, cursors, relayed_murmurs, pruning, and related operations.
Whisper store refactor & tests
internal/whisper/store/store.go, internal/whisper/store/schema.go, internal/whisper/store/store_coverage_test.go
Refactor to use whisperdb sqlc methods, embed schema via //go:embed, add toNullString helper, and update tests to validate sql.NullString behavior.
sqlc config
sqlc.yaml
Add sqlc configuration for CodeDB and Whisper generation targets.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(200,200,255,0.5)
    participant Indexer
    end
    rect rgba(200,255,200,0.5)
    participant Queries
    end
    rect rgba(255,200,200,0.5)
    participant DB
    end
    rect rgba(255,255,200,0.5)
    participant Bleve
    end

    Indexer->>Queries: ListFileMtimes(ctx) / GetPRIDByNumber(ctx)
    Queries->>DB: QueryContext / QueryRowContext
    DB-->>Queries: rows / row
    Queries-->>Indexer: typed results (IDs, rows)
    Indexer->>Queries: InsertPullRequest/InsertPRComment/UpsertFileMtime(ctx, params)
    Queries->>DB: ExecContext inserts/deletes/upserts
    Indexer->>Bleve: Index file content using resolved DB IDs
    Bleve-->>Indexer: index result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐇 I hop through rows and bind each name,
Nulls now proper, contexts in frame.
sqlc seeds sprout typed queries bright,
Indexers hum deep into the night.
A little carrot for a tidy DB — hooray! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding sqlc-generated typed SQL to two database stores (whisper and codedb), which aligns with the core PR objective.

✏️ 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 ryan/sqlc-typed-sql

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

@rsnodgrass rsnodgrass marked this pull request as ready for review March 29, 2026 10:27
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
internal/codedb/sqlc/queries/repos.sql (1)

8-15: Make list queries deterministic and harden ref join integrity.

Line 9, Line 12, and Line 15 return unordered result sets; this can cause nondeterministic behavior upstream. Also on Line 15, adding c.repo_id = r.repo_id is a good defensive guard for data integrity.

♻️ Proposed SQL refinement
 -- name: ListRepoPaths :many
-SELECT path FROM repos;
+SELECT path FROM repos
+ORDER BY path;

 -- name: ListCommitHashesByRepo :many
-SELECT hash FROM commits WHERE repo_id = ?;
+SELECT hash FROM commits
+WHERE repo_id = ?
+ORDER BY hash;

 -- name: ListRefsByRepo :many
-SELECT r.name, c.hash FROM refs r JOIN commits c ON r.commit_id = c.id WHERE r.repo_id = ?;
+SELECT r.name, c.hash
+FROM refs r
+JOIN commits c
+  ON r.commit_id = c.id
+ AND c.repo_id = r.repo_id
+WHERE r.repo_id = ?
+ORDER BY r.name;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/codedb/sqlc/queries/repos.sql` around lines 8 - 15, The three SQL
queries (ListRepoPaths, ListCommitHashesByRepo, ListRefsByRepo) return unordered
rows — make them deterministic by adding explicit ORDER BY clauses (e.g., ORDER
BY path for ListRepoPaths, ORDER BY hash for ListCommitHashesByRepo, and ORDER
BY r.name[, c.hash] for ListRefsByRepo) and harden the ref join in
ListRefsByRepo by adding the defensive join predicate c.repo_id = r.repo_id to
the WHERE/JOIN condition so refs cannot join to a commit from a different repo.
internal/whisper/store/store.go (1)

304-315: Minor: Inconsistent UTC normalization for RelayedAt timestamp.

Line 309 uses time.Now().Format(...) without .UTC(), while other timestamp formatting in this file (lines 218, 277, 433-434) consistently applies .UTC() before formatting. This won't cause bugs since RFC3339 includes timezone info, but consistency aids readability.

🔧 Optional consistency fix
-		RelayedAt: time.Now().Format(time.RFC3339Nano),
+		RelayedAt: time.Now().UTC().Format(time.RFC3339Nano),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/whisper/store/store.go` around lines 304 - 315, The RelayedAt
timestamp in MarkRelayed uses time.Now().Format(...) while other timestamps use
UTC; update the call in Store.MarkRelayed so RelayedAt is generated with
time.Now().UTC().Format(time.RFC3339Nano) when building the
whisperdb.MarkRelayedParams passed to s.queries.MarkRelayed to match the file's
UTC normalization convention.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/codedb/index/indexer.go`:
- Around line 884-890: The code in indexer.go treats a failed diff-ID lookup
from q.GetDiffIDByCommitPath (used to populate diffDBID) as a success by
returning nil, which causes the commit to proceed without creating the Bleve
document; change the error handling so the lookup failure is propagated instead
of swallowed: when q.GetDiffIDByCommitPath returns an error, return that error
(or wrap it with context) from the surrounding function (the function containing
diffDBID), so callers know the indexing step failed and can retry or abort
rather than silently skipping Bleve indexing.

In `@internal/codedb/sqlc/schema.sql`:
- Around line 11-18: The commits table currently mixes repo-scoped repo_id with
a globally UNIQUE hash which causes collisions for forks; update the schema and
runtime DDL to use a consistent model—preferably make commits repo-scoped by
replacing the UNIQUE(hash) constraint with UNIQUE(repo_id, hash) (or
alternatively remove repo_id if you want global deduplication) and then update
code that queries commits (e.g., loadKnownCommits in
internal/codedb/index/indexer.go) to perform repo-aware lookups using repo_id
plus hash; ensure the chosen change is reflected in both the CREATE TABLE DDL
and any runtime migrations/DDL applied by the app.

---

Nitpick comments:
In `@internal/codedb/sqlc/queries/repos.sql`:
- Around line 8-15: The three SQL queries (ListRepoPaths,
ListCommitHashesByRepo, ListRefsByRepo) return unordered rows — make them
deterministic by adding explicit ORDER BY clauses (e.g., ORDER BY path for
ListRepoPaths, ORDER BY hash for ListCommitHashesByRepo, and ORDER BY r.name[,
c.hash] for ListRefsByRepo) and harden the ref join in ListRefsByRepo by adding
the defensive join predicate c.repo_id = r.repo_id to the WHERE/JOIN condition
so refs cannot join to a commit from a different repo.

In `@internal/whisper/store/store.go`:
- Around line 304-315: The RelayedAt timestamp in MarkRelayed uses
time.Now().Format(...) while other timestamps use UTC; update the call in
Store.MarkRelayed so RelayedAt is generated with
time.Now().UTC().Format(time.RFC3339Nano) when building the
whisperdb.MarkRelayedParams passed to s.queries.MarkRelayed to match the file's
UTC normalization convention.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97a55144-8567-4d20-9464-975ab4f44b4e

📥 Commits

Reviewing files that changed from the base of the PR and between fca6b9a and aa8640d.

📒 Files selected for processing (31)
  • internal/codedb/index/github.go
  • internal/codedb/index/helpers_test.go
  • internal/codedb/index/indexer.go
  • internal/codedb/index/indexer_coverage_test.go
  • internal/codedb/sqlc/blobs.sql.go
  • internal/codedb/sqlc/commits.sql.go
  • internal/codedb/sqlc/db.go
  • internal/codedb/sqlc/diffs.sql.go
  • internal/codedb/sqlc/file_revs.sql.go
  • internal/codedb/sqlc/github.sql.go
  • internal/codedb/sqlc/models.go
  • internal/codedb/sqlc/queries/blobs.sql
  • internal/codedb/sqlc/queries/commits.sql
  • internal/codedb/sqlc/queries/diffs.sql
  • internal/codedb/sqlc/queries/file_revs.sql
  • internal/codedb/sqlc/queries/github.sql
  • internal/codedb/sqlc/queries/refs.sql
  • internal/codedb/sqlc/queries/repos.sql
  • internal/codedb/sqlc/refs.sql.go
  • internal/codedb/sqlc/repos.sql.go
  • internal/codedb/sqlc/schema.sql
  • internal/codedb/store/store.go
  • internal/whisper/store/schema.go
  • internal/whisper/store/sqlc/db.go
  • internal/whisper/store/sqlc/models.go
  • internal/whisper/store/sqlc/queries.sql
  • internal/whisper/store/sqlc/queries.sql.go
  • internal/whisper/store/sqlc/schema.sql
  • internal/whisper/store/store.go
  • internal/whisper/store/store_coverage_test.go
  • sqlc.yaml

@rsnodgrass rsnodgrass force-pushed the ryan/sqlc-typed-sql branch from aa8640d to 7d722e2 Compare March 29, 2026 12:03
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
internal/codedb/index/indexer.go (1)

1060-1066: ⚠️ Potential issue | 🟠 Major

Diff-ID lookup failures should not be treated as success.

At Line 1065, returning nil suppresses a real indexing failure and can leave SQL and Bleve out of sync for that diff path.

Suggested fix
 diffDBID, err := q.GetDiffIDByCommitPath(ctx, codedbsqlc.GetDiffIDByCommitPathParams{
 	CommitID: commitDBID,
 	Path:     path,
 })
 if err != nil {
-	return nil // non-fatal: skip Bleve indexing for this diff
+	return fmt.Errorf("get diff id: %w", err)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/codedb/index/indexer.go` around lines 1060 - 1066, The current code
treats failures from q.GetDiffIDByCommitPath (called with
codedbsqlc.GetDiffIDByCommitPathParams using commitDBID and path) as a success
by returning nil, which hides real indexing errors; change the handling to
propagate the error instead of returning nil (e.g., return fmt.Errorf or the
original err) so the caller knows Bleve indexing for that diff failed, or
explicitly log the error and return it from the enclosing function; ensure the
returned error is used by the caller that invokes this block so SQL and Bleve
remain in sync.
🧹 Nitpick comments (2)
internal/codedb/index/helpers_test.go (2)

71-83: Consider table-driven pattern for consistency.

The test is functionally correct, but unlike TestTimeToNullInt64 above, it doesn't use the table-driven approach. For consistency and easier extensibility (e.g., adding whitespace-only string tests later), consider refactoring.

♻️ Optional: table-driven refactor
 func TestToNullString(t *testing.T) {
 	t.Parallel()
 
-	got := toNullString("")
-	if got.Valid {
-		t.Error("empty string should be invalid")
-	}
-
-	got = toNullString("hello")
-	if !got.Valid || got.String != "hello" {
-		t.Errorf("expected valid 'hello', got valid=%v string=%q", got.Valid, got.String)
+	tests := []struct {
+		name       string
+		input      string
+		wantValid  bool
+		wantString string
+	}{
+		{"empty string is invalid", "", false, ""},
+		{"non-empty string is valid", "hello", true, "hello"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := toNullString(tt.input)
+			if got.Valid != tt.wantValid {
+				t.Errorf("valid = %v, want %v", got.Valid, tt.wantValid)
+			}
+			if got.Valid && got.String != tt.wantString {
+				t.Errorf("string = %q, want %q", got.String, tt.wantString)
+			}
+		})
 	}
 }

As per coding guidelines: "Use table-driven tests for test cases; cover both success and error paths"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/codedb/index/helpers_test.go` around lines 71 - 83, Refactor
TestToNullString to use a table-driven pattern like TestTimeToNullInt64: create
a slice of test cases (e.g., name, input string, wantValid bool, wantString
string), iterate with t.Run for each case, assert got := toNullString(input)
against wantValid and wantString, and include cases for empty string and a
normal string (and optionally whitespace-only) to keep consistency and make
future additions easier.

85-98: Same suggestion: consider table-driven pattern.

Similar to TestToNullString, this test could be refactored to use table-driven tests for consistency with the rest of the file.

♻️ Optional: table-driven refactor
 func TestPtrIntToNullInt64(t *testing.T) {
 	t.Parallel()
 
-	got := ptrIntToNullInt64(nil)
-	if got.Valid {
-		t.Error("nil should be invalid")
-	}
-
-	n := 42
-	got = ptrIntToNullInt64(&n)
-	if !got.Valid || got.Int64 != 42 {
-		t.Errorf("expected valid 42, got valid=%v int64=%d", got.Valid, got.Int64)
+	n := 42
+	tests := []struct {
+		name      string
+		input     *int
+		wantValid bool
+		wantInt64 int64
+	}{
+		{"nil is invalid", nil, false, 0},
+		{"non-nil is valid", &n, true, 42},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := ptrIntToNullInt64(tt.input)
+			if got.Valid != tt.wantValid {
+				t.Errorf("valid = %v, want %v", got.Valid, tt.wantValid)
+			}
+			if got.Valid && got.Int64 != tt.wantInt64 {
+				t.Errorf("int64 = %d, want %d", got.Int64, tt.wantInt64)
+			}
+		})
 	}
 }

As per coding guidelines: "Use table-driven tests for test cases"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/codedb/index/helpers_test.go` around lines 85 - 98, Refactor
TestPtrIntToNullInt64 into a table-driven test to match the file's style: create
a slice of test cases with name, input (*int) and expected validity/Int64,
iterate with t.Run for each case, and replace the two existing assertions by
table assertions; update references to ptrIntToNullInt64 and keep t.Parallel()
inside the top-level test or per-subtest as appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/codedb/index/indexer.go`:
- Around line 589-595: The code creates a fresh context via context.Background()
which drops caller cancellation and deadlines; replace that local ctx with the
incoming caller context (i.e., stop shadowing/creating ctx and use the
function's ctx parameter) so the sqlc calls use the propagated context for
UpsertRepo, GetRepoIDByName and the other queries referenced (lines around the
UpsertRepo/GetRepoIDByName calls and the similar sites at 603, 616, 1427).
Ensure you remove the context.Background() assignment, pass the existing ctx to
s.Queries().UpsertRepo/GetRepoIDByName (and the other query calls) so
cancellations/timeouts propagate correctly.
- Around line 923-927: The code in the parent linking loop treats any error from
q.GetCommitIDByHash(ctx, parentHex) as “parent missing” and continues, which
hides real DB errors; update the error handling in the block that sets
parentDBID to use errors.Is(err, sql.ErrNoRows) (or the package-specific
ErrNoRows) to detect the “not found” case and continue only then, but for all
other errors wrap the error with context (including parentHex and the calling
function or commit ID) and return or propagate it instead of continuing;
reference the call to q.GetCommitIDByHash, the parentHex variable, and the
parentDBID assignment when making the change.

---

Duplicate comments:
In `@internal/codedb/index/indexer.go`:
- Around line 1060-1066: The current code treats failures from
q.GetDiffIDByCommitPath (called with codedbsqlc.GetDiffIDByCommitPathParams
using commitDBID and path) as a success by returning nil, which hides real
indexing errors; change the handling to propagate the error instead of returning
nil (e.g., return fmt.Errorf or the original err) so the caller knows Bleve
indexing for that diff failed, or explicitly log the error and return it from
the enclosing function; ensure the returned error is used by the caller that
invokes this block so SQL and Bleve remain in sync.

---

Nitpick comments:
In `@internal/codedb/index/helpers_test.go`:
- Around line 71-83: Refactor TestToNullString to use a table-driven pattern
like TestTimeToNullInt64: create a slice of test cases (e.g., name, input
string, wantValid bool, wantString string), iterate with t.Run for each case,
assert got := toNullString(input) against wantValid and wantString, and include
cases for empty string and a normal string (and optionally whitespace-only) to
keep consistency and make future additions easier.
- Around line 85-98: Refactor TestPtrIntToNullInt64 into a table-driven test to
match the file's style: create a slice of test cases with name, input (*int) and
expected validity/Int64, iterate with t.Run for each case, and replace the two
existing assertions by table assertions; update references to ptrIntToNullInt64
and keep t.Parallel() inside the top-level test or per-subtest as appropriate.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 307a9ea7-f855-4a00-b8d5-77058ccdd8aa

📥 Commits

Reviewing files that changed from the base of the PR and between aa8640d and 7d722e2.

📒 Files selected for processing (17)
  • internal/codedb/index/github.go
  • internal/codedb/index/helpers_test.go
  • internal/codedb/index/indexer.go
  • internal/codedb/index/indexer_coverage_test.go
  • internal/codedb/sqlc/blobs.sql.go
  • internal/codedb/sqlc/commits.sql.go
  • internal/codedb/sqlc/db.go
  • internal/codedb/sqlc/diffs.sql.go
  • internal/codedb/sqlc/file_revs.sql.go
  • internal/codedb/sqlc/github.sql.go
  • internal/codedb/sqlc/models.go
  • internal/codedb/sqlc/queries/blobs.sql
  • internal/codedb/sqlc/queries/commits.sql
  • internal/codedb/sqlc/queries/diffs.sql
  • internal/codedb/sqlc/queries/file_revs.sql
  • internal/codedb/sqlc/queries/github.sql
  • internal/codedb/sqlc/queries/refs.sql
✅ Files skipped from review due to trivial changes (10)
  • internal/codedb/sqlc/queries/diffs.sql
  • internal/codedb/sqlc/queries/blobs.sql
  • internal/codedb/sqlc/db.go
  • internal/codedb/sqlc/diffs.sql.go
  • internal/codedb/sqlc/blobs.sql.go
  • internal/codedb/sqlc/commits.sql.go
  • internal/codedb/sqlc/file_revs.sql.go
  • internal/codedb/sqlc/queries/commits.sql
  • internal/codedb/sqlc/queries/github.sql
  • internal/codedb/sqlc/github.sql.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/codedb/sqlc/queries/refs.sql
  • internal/codedb/index/indexer_coverage_test.go
  • internal/codedb/sqlc/queries/file_revs.sql
  • internal/codedb/index/github.go

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
internal/codedb/index/indexer.go (3)

589-595: ⚠️ Potential issue | 🟠 Major

Propagate the caller ctx through these sqlc/store helpers.

These paths are all reached from cancellation-aware indexing/parsing flows, but each helper swaps that for context.Background(). That drops deadlines/cancellation and can keep DB work running after the caller has already aborted. Please thread the incoming ctx into upsertRepo, loadKnownCommits, loadExistingRefs, insertParentLinks, insertDiff, buildTipFileRevs, ensureBlob, and openReposFromDB.

Also applies to: 603-603, 616-616, 915-916, 1043-1044, 1081-1082, 1198-1200, 1427-1427

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/codedb/index/indexer.go` around lines 589 - 595, Current code
creates a new context with context.Background() before calling SQL helpers,
dropping deadlines/cancellation; instead thread the incoming caller ctx into
these DB helper calls. Replace usages like ctx := context.Background() and
subsequent q.UpsertRepo/GetRepoIDByName with the passed-in ctx, and update
helper signatures and callsites for upsertRepo, loadKnownCommits,
loadExistingRefs, insertParentLinks, insertDiff, buildTipFileRevs, ensureBlob,
and openReposFromDB so they accept a context parameter and use it when calling
s.Queries() and sqlc methods; ensure all call sites propagate the original ctx
through the call chain to preserve cancellation/deadlines.

923-926: ⚠️ Potential issue | 🟠 Major

Don't treat every parent lookup failure as “missing”.

Only sql.ErrNoRows should skip the link. Any other error here silently drops a commit-parent edge and leaves the commit graph incomplete.
As per coding guidelines: "Use errors.Is() and errors.As() for error checking and type assertion; wrap errors with context".

💡 Suggested fix
+import "errors"
...
 		parentDBID, err = q.GetCommitIDByHash(ctx, parentHex)
 		if err != nil {
-			continue // parent not yet in DB; skip link
+			if errors.Is(err, sql.ErrNoRows) {
+				continue // parent not yet in DB; skip link
+			}
+			return fmt.Errorf("get parent commit id %s: %w", parentHex, err)
 		}
+		st.commitIDCache[parentHex] = parentDBID
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/codedb/index/indexer.go` around lines 923 - 926, The code currently
treats any error from q.GetCommitIDByHash(ctx, parentHex) as "missing" and
silently continues; change this in the parent link block so only sql.ErrNoRows
results in skipping the link. Specifically, call q.GetCommitIDByHash and if err
!= nil use errors.Is(err, sql.ErrNoRows) to continue, otherwise wrap/return or
log the error with context (use fmt.Errorf or errors.Wrap-like pattern) so
unexpected DB errors are not dropped; update the handling around parentDBID, err
and ensure the error path uses the same context and propagation style as other
DB errors in this file.

1060-1065: ⚠️ Potential issue | 🟠 Major

Propagate diff-ID lookup failures.

Returning nil here commits the SQL diff row but skips the Bleve document, so later runs treat the commit as indexed while diff search stays stale for this path.

💡 Suggested fix
 diffDBID, err := q.GetDiffIDByCommitPath(ctx, codedbsqlc.GetDiffIDByCommitPathParams{
 	CommitID: commitDBID,
 	Path:     path,
 })
 if err != nil {
-	return nil // non-fatal: skip Bleve indexing for this diff
+	return fmt.Errorf("get diff id for commit %d path %q: %w", commitDBID, path, err)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/codedb/index/indexer.go` around lines 1060 - 1065, The call to
q.GetDiffIDByCommitPath (using commitDBID and path) currently swallows errors by
returning nil, causing the SQL diff row to be committed while Bleve indexing is
skipped; change this to propagate the error instead of returning nil (e.g.,
return the error or a wrapped error) so callers know Bleve indexing failed;
update the surrounding function (in indexer.go) to return the error from
GetDiffIDByCommitPath (or wrap it with context) so upstream can handle/retry
instead of marking the commit as fully indexed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/codedb/index/indexer.go`:
- Around line 1085-1087: The code treats any error from GetCommitIDByHash and
GetBlobIDByHash as "not found" which hides real DB failures; update callers
(e.g., buildTipFileRevs) and the blob insertion path to check errors.Is(err,
sql.ErrNoRows) for lookup-misses and only treat that case as a not-found/skip,
but for any other error return a wrapped error (use fmt.Errorf or errors.Wrap)
so real DB failures surface; specifically modify the buildTipFileRevs call
handling of GetCommitIDByHash to return the error when it's not sql.ErrNoRows,
and change the GetBlobIDByHash/InsertBlob flow to abort and return the wrapped
DB error instead of silently falling through when the error is not
sql.ErrNoRows.

---

Duplicate comments:
In `@internal/codedb/index/indexer.go`:
- Around line 589-595: Current code creates a new context with
context.Background() before calling SQL helpers, dropping
deadlines/cancellation; instead thread the incoming caller ctx into these DB
helper calls. Replace usages like ctx := context.Background() and subsequent
q.UpsertRepo/GetRepoIDByName with the passed-in ctx, and update helper
signatures and callsites for upsertRepo, loadKnownCommits, loadExistingRefs,
insertParentLinks, insertDiff, buildTipFileRevs, ensureBlob, and openReposFromDB
so they accept a context parameter and use it when calling s.Queries() and sqlc
methods; ensure all call sites propagate the original ctx through the call chain
to preserve cancellation/deadlines.
- Around line 923-926: The code currently treats any error from
q.GetCommitIDByHash(ctx, parentHex) as "missing" and silently continues; change
this in the parent link block so only sql.ErrNoRows results in skipping the
link. Specifically, call q.GetCommitIDByHash and if err != nil use
errors.Is(err, sql.ErrNoRows) to continue, otherwise wrap/return or log the
error with context (use fmt.Errorf or errors.Wrap-like pattern) so unexpected DB
errors are not dropped; update the handling around parentDBID, err and ensure
the error path uses the same context and propagation style as other DB errors in
this file.
- Around line 1060-1065: The call to q.GetDiffIDByCommitPath (using commitDBID
and path) currently swallows errors by returning nil, causing the SQL diff row
to be committed while Bleve indexing is skipped; change this to propagate the
error instead of returning nil (e.g., return the error or a wrapped error) so
callers know Bleve indexing failed; update the surrounding function (in
indexer.go) to return the error from GetDiffIDByCommitPath (or wrap it with
context) so upstream can handle/retry instead of marking the commit as fully
indexed.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 20d01fea-6a84-4fca-affe-0ed5b80fe0d2

📥 Commits

Reviewing files that changed from the base of the PR and between 7d722e2 and 1e8c07c.

📒 Files selected for processing (3)
  • internal/codedb/index/indexer.go
  • internal/codedb/sqlc/queries/symbols.sql
  • internal/codedb/sqlc/symbols.sql.go
✅ Files skipped from review due to trivial changes (1)
  • internal/codedb/sqlc/queries/symbols.sql

@rsnodgrass rsnodgrass force-pushed the ryan/sqlc-typed-sql branch from 8924458 to c0caa2e Compare March 29, 2026 12:23
@rsnodgrass rsnodgrass merged commit af0af58 into main Mar 29, 2026
1 of 2 checks passed
@rsnodgrass rsnodgrass deleted the ryan/sqlc-typed-sql branch March 29, 2026 12:25
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