Skip to content

Commit e6eb2df

Browse files
committed
Fix GetDependenciesAtCommit using lexicographic SHA comparison
The query used WHERE c.sha <= ? to find the nearest snapshot, but SHA hex strings don't sort in commit order. Replaced with a position-based join through branch_commits, matching how GetDependenciesAtRef works.
1 parent b676ce9 commit e6eb2df

File tree

2 files changed

+94
-5
lines changed

2 files changed

+94
-5
lines changed

internal/database/database_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,93 @@ func TestStoreSnapshotWithDuplicates(t *testing.T) {
372372
}
373373
}
374374

375+
func TestGetDependenciesAtCommit(t *testing.T) {
376+
tmpDir := t.TempDir()
377+
dbPath := filepath.Join(tmpDir, "pkgs.sqlite3")
378+
379+
db, err := database.Create(dbPath)
380+
if err != nil {
381+
t.Fatalf("failed to create database: %v", err)
382+
}
383+
defer func() { _ = db.Close() }()
384+
385+
branch, err := db.GetOrCreateBranch("main")
386+
if err != nil {
387+
t.Fatalf("failed to create branch: %v", err)
388+
}
389+
390+
// Create commits in order. SHA hex values are intentionally chosen so that
391+
// lexicographic order differs from commit order:
392+
// commit 1 (position 1): SHA "ff0001" (lexicographically last)
393+
// commit 2 (position 2): SHA "000002" (lexicographically first)
394+
// commit 3 (position 3): SHA "880003" (lexicographically middle)
395+
commits := []database.CommitInfo{
396+
{SHA: "ff0001", Message: "first commit"},
397+
{SHA: "000002", Message: "second commit"},
398+
{SHA: "880003", Message: "third commit"},
399+
}
400+
401+
// Store snapshot at commit 1 with lodash
402+
err = db.StoreSnapshot(branch.ID, commits[0], []database.SnapshotInfo{
403+
{ManifestPath: "package.json", Name: "lodash", Ecosystem: "npm", Requirement: "4.0.0"},
404+
})
405+
if err != nil {
406+
t.Fatalf("failed to store snapshot 1: %v", err)
407+
}
408+
409+
// Store commit 2 (no snapshot, just link it to the branch)
410+
err = db.StoreSnapshot(branch.ID, commits[1], []database.SnapshotInfo{
411+
{ManifestPath: "package.json", Name: "lodash", Ecosystem: "npm", Requirement: "4.0.0"},
412+
{ManifestPath: "package.json", Name: "react", Ecosystem: "npm", Requirement: "18.0.0"},
413+
})
414+
if err != nil {
415+
t.Fatalf("failed to store snapshot 2: %v", err)
416+
}
417+
418+
// Query dependencies at commit 3 (no snapshot at this commit, should get
419+
// the snapshot from commit 2 since it's earlier in position order, not
420+
// commit 1 which would be wrong if using lexicographic SHA comparison)
421+
err = db.StoreSnapshot(branch.ID, commits[2], []database.SnapshotInfo{
422+
{ManifestPath: "package.json", Name: "lodash", Ecosystem: "npm", Requirement: "4.0.0"},
423+
{ManifestPath: "package.json", Name: "react", Ecosystem: "npm", Requirement: "18.0.0"},
424+
{ManifestPath: "package.json", Name: "express", Ecosystem: "npm", Requirement: "4.18.0"},
425+
})
426+
if err != nil {
427+
t.Fatalf("failed to store snapshot 3: %v", err)
428+
}
429+
430+
// Query at commit 2 -- should get the snapshot stored at commit 2 (position 2)
431+
deps, err := db.GetDependenciesAtCommit("000002")
432+
if err != nil {
433+
t.Fatalf("GetDependenciesAtCommit failed: %v", err)
434+
}
435+
436+
if len(deps) != 2 {
437+
t.Fatalf("expected 2 dependencies at commit 2, got %d", len(deps))
438+
}
439+
440+
names := map[string]bool{}
441+
for _, d := range deps {
442+
names[d.Name] = true
443+
}
444+
if !names["lodash"] || !names["react"] {
445+
t.Errorf("expected lodash and react, got %v", names)
446+
}
447+
448+
// Query at commit 1 -- should get only lodash (not react, which was added later)
449+
deps, err = db.GetDependenciesAtCommit("ff0001")
450+
if err != nil {
451+
t.Fatalf("GetDependenciesAtCommit at commit 1 failed: %v", err)
452+
}
453+
454+
if len(deps) != 1 {
455+
t.Fatalf("expected 1 dependency at commit 1, got %d", len(deps))
456+
}
457+
if deps[0].Name != "lodash" {
458+
t.Errorf("expected lodash at commit 1, got %s", deps[0].Name)
459+
}
460+
}
461+
375462
func TestSchemaIndexes(t *testing.T) {
376463
tmpDir := t.TempDir()
377464
dbPath := filepath.Join(tmpDir, "pkgs.sqlite3")

internal/database/queries.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,17 @@ type Dependency struct {
246246
}
247247

248248
func (db *DB) GetDependenciesAtCommit(sha string) ([]Dependency, error) {
249-
// Find the most recent snapshot at or before this commit
249+
// Find the most recent snapshot at or before this commit using position
250250
var commitID int64
251251
err := db.QueryRow(`
252252
SELECT ds.commit_id
253253
FROM dependency_snapshots ds
254-
JOIN commits c ON c.id = ds.commit_id
255-
JOIN branch_commits bc ON bc.commit_id = c.id
256-
WHERE c.sha <= ?
257-
ORDER BY bc.position DESC
254+
JOIN branch_commits snap_bc ON snap_bc.commit_id = ds.commit_id
255+
JOIN commits c ON c.sha = ?
256+
JOIN branch_commits target_bc ON target_bc.commit_id = c.id
257+
AND target_bc.branch_id = snap_bc.branch_id
258+
WHERE snap_bc.position <= target_bc.position
259+
ORDER BY snap_bc.position DESC
258260
LIMIT 1
259261
`, sha).Scan(&commitID)
260262
if err == sql.ErrNoRows {

0 commit comments

Comments
 (0)