Centralize error handling patterns in storage layer (bd-bwk2)

Standardized error handling across the SQLite storage layer by
consistently using wrapDBError() helper functions that were already
defined in errors.go.

Changes:
- config.go: Applied wrapDBError to all config/metadata functions
- queries.go: Fixed bare 'return err' in CreateIssue, UpdateIssue, DeleteIssues
- store.go: Changed %v to %w for proper error chain preservation
- errors_test.go: Added comprehensive test coverage for error wrapping

All error paths now:
- Wrap errors with operation context using %w
- Convert sql.ErrNoRows to ErrNotFound consistently
- Preserve error chains for unwrapping and type checking

This improves debugging by maintaining operation context throughout
the error chain and enables type-safe error checking with sentinel
errors.

All tests passing ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-11-24 00:59:49 -08:00
parent 8d6696af40
commit 55fdaf99e7
5 changed files with 273 additions and 21 deletions

View File

@@ -11,7 +11,7 @@ func (s *SQLiteStorage) SetConfig(ctx context.Context, key, value string) error
INSERT INTO config (key, value) VALUES (?, ?)
ON CONFLICT (key) DO UPDATE SET value = excluded.value
`, key, value)
return err
return wrapDBError("set config", err)
}
// GetConfig gets a configuration value
@@ -21,14 +21,14 @@ func (s *SQLiteStorage) GetConfig(ctx context.Context, key string) (string, erro
if err == sql.ErrNoRows {
return "", nil
}
return value, err
return value, wrapDBError("get config", err)
}
// GetAllConfig gets all configuration key-value pairs
func (s *SQLiteStorage) GetAllConfig(ctx context.Context) (map[string]string, error) {
rows, err := s.db.QueryContext(ctx, `SELECT key, value FROM config ORDER BY key`)
if err != nil {
return nil, err
return nil, wrapDBError("query all config", err)
}
defer func() { _ = rows.Close() }()
@@ -36,17 +36,17 @@ func (s *SQLiteStorage) GetAllConfig(ctx context.Context) (map[string]string, er
for rows.Next() {
var key, value string
if err := rows.Scan(&key, &value); err != nil {
return nil, err
return nil, wrapDBError("scan config row", err)
}
config[key] = value
}
return config, rows.Err()
return config, wrapDBError("iterate config rows", rows.Err())
}
// DeleteConfig deletes a configuration value
func (s *SQLiteStorage) DeleteConfig(ctx context.Context, key string) error {
_, err := s.db.ExecContext(ctx, `DELETE FROM config WHERE key = ?`, key)
return err
return wrapDBError("delete config", err)
}
// OrphanHandling defines how to handle orphan issues during import
@@ -81,7 +81,7 @@ func (s *SQLiteStorage) SetMetadata(ctx context.Context, key, value string) erro
INSERT INTO metadata (key, value) VALUES (?, ?)
ON CONFLICT (key) DO UPDATE SET value = excluded.value
`, key, value)
return err
return wrapDBError("set metadata", err)
}
// GetMetadata gets a metadata value (for internal state like import hashes)
@@ -91,5 +91,5 @@ func (s *SQLiteStorage) GetMetadata(ctx context.Context, key string) (string, er
if err == sql.ErrNoRows {
return "", nil
}
return value, err
return value, wrapDBError("get metadata", err)
}