Implement deferred core utility parity APIs/tests and refresh tracking artifacts

This commit is contained in:
Joseph Doherty
2026-02-27 10:27:05 -05:00
parent c0aaae9236
commit b94a67be6e
17 changed files with 842 additions and 9 deletions

View File

@@ -152,3 +152,176 @@ func (w *DBWriter) insertLibrary(tx *sql.Tx, imp *ImportInfo) error {
)
return err
}
// OpenDBNoSchema opens an existing SQLite database without applying schema.
// It verifies that the required tables exist.
func OpenDBNoSchema(dbPath string) (*sql.DB, error) {
db, err := sql.Open("sqlite3", dbPath+"?_journal_mode=WAL&_foreign_keys=ON")
if err != nil {
return nil, fmt.Errorf("opening database: %w", err)
}
// Verify required tables exist
for _, table := range []string{"modules", "features", "unit_tests", "dependencies"} {
var name string
err := db.QueryRow("SELECT name FROM sqlite_master WHERE type='table' AND name=?", table).Scan(&name)
if err != nil {
db.Close()
return nil, fmt.Errorf("required table %q not found: %w", table, err)
}
}
return db, nil
}
// CallGraphStats holds summary statistics from a call-graph update.
type CallGraphStats struct {
TestsAnalyzed int
TestsLinked int
DependencyRows int
FeatureIDsSet int
}
// UpdateCallGraph writes call-graph analysis results to the database incrementally.
func (w *DBWriter) UpdateCallGraph(result *AnalysisResult) (*CallGraphStats, error) {
stats := &CallGraphStats{}
// Load module name→ID mapping
moduleIDs := make(map[string]int64)
rows, err := w.db.Query("SELECT id, name FROM modules")
if err != nil {
return nil, fmt.Errorf("querying modules: %w", err)
}
for rows.Next() {
var id int64
var name string
if err := rows.Scan(&id, &name); err != nil {
rows.Close()
return nil, err
}
moduleIDs[name] = id
}
rows.Close()
// Load feature DB IDs: "module_name:go_method:go_class" → id
type featureKey struct {
moduleName string
goMethod string
goClass string
}
featureDBIDs := make(map[featureKey]int64)
rows, err = w.db.Query(`
SELECT f.id, m.name, f.go_method, COALESCE(f.go_class, '')
FROM features f
JOIN modules m ON f.module_id = m.id
`)
if err != nil {
return nil, fmt.Errorf("querying features: %w", err)
}
for rows.Next() {
var id int64
var modName, goMethod, goClass string
if err := rows.Scan(&id, &modName, &goMethod, &goClass); err != nil {
rows.Close()
return nil, err
}
featureDBIDs[featureKey{modName, goMethod, goClass}] = id
}
rows.Close()
// Load test DB IDs: "module_name:go_method" → id
testDBIDs := make(map[string]int64)
rows, err = w.db.Query(`
SELECT ut.id, m.name, ut.go_method
FROM unit_tests ut
JOIN modules m ON ut.module_id = m.id
`)
if err != nil {
return nil, fmt.Errorf("querying unit_tests: %w", err)
}
for rows.Next() {
var id int64
var modName, goMethod string
if err := rows.Scan(&id, &modName, &goMethod); err != nil {
rows.Close()
return nil, err
}
testDBIDs[modName+":"+goMethod] = id
}
rows.Close()
// Begin transaction
tx, err := w.db.Begin()
if err != nil {
return nil, fmt.Errorf("beginning transaction: %w", err)
}
defer tx.Rollback()
// Clear old call-graph data
if _, err := tx.Exec("DELETE FROM dependencies WHERE source_type='unit_test' AND dependency_kind='calls'"); err != nil {
return nil, fmt.Errorf("clearing old dependencies: %w", err)
}
if _, err := tx.Exec("UPDATE unit_tests SET feature_id = NULL"); err != nil {
return nil, fmt.Errorf("clearing old feature_ids: %w", err)
}
// Prepare statements
insertDep, err := tx.Prepare("INSERT OR IGNORE INTO dependencies (source_type, source_id, target_type, target_id, dependency_kind) VALUES ('unit_test', ?, 'feature', ?, 'calls')")
if err != nil {
return nil, fmt.Errorf("preparing insert dependency: %w", err)
}
defer insertDep.Close()
updateFeatureID, err := tx.Prepare("UPDATE unit_tests SET feature_id = ? WHERE id = ?")
if err != nil {
return nil, fmt.Errorf("preparing update feature_id: %w", err)
}
defer updateFeatureID.Close()
// Process each module's tests
for _, mod := range result.Modules {
for _, test := range mod.Tests {
stats.TestsAnalyzed++
testDBID, ok := testDBIDs[mod.Name+":"+test.GoMethod]
if !ok {
continue
}
// Insert dependency rows for linked features
if len(test.LinkedFeatures) > 0 {
stats.TestsLinked++
}
for _, fi := range test.LinkedFeatures {
feat := mod.Features[fi]
featDBID, ok := featureDBIDs[featureKey{mod.Name, feat.GoMethod, feat.GoClass}]
if !ok {
continue
}
if _, err := insertDep.Exec(testDBID, featDBID); err != nil {
return nil, fmt.Errorf("inserting dependency for test %s: %w", test.GoMethod, err)
}
stats.DependencyRows++
}
// Set feature_id for best match
if test.BestFeatureIdx >= 0 {
feat := mod.Features[test.BestFeatureIdx]
featDBID, ok := featureDBIDs[featureKey{mod.Name, feat.GoMethod, feat.GoClass}]
if !ok {
continue
}
if _, err := updateFeatureID.Exec(featDBID, testDBID); err != nil {
return nil, fmt.Errorf("updating feature_id for test %s: %w", test.GoMethod, err)
}
stats.FeatureIDsSet++
}
}
}
if err := tx.Commit(); err != nil {
return nil, fmt.Errorf("committing transaction: %w", err)
}
return stats, nil
}