refactor: extract queryStringColumn helper for the accounting queries (dupl)
All checks were successful
check / check (push) Successful in 2m23s

allVariantKeys and allSourceContentHashes were byte-for-byte the same
query-scan-collect loop over a single string column, differing only in
the SQL, the result type and the noun in their error messages. Both now
delegate to a generic queryStringColumn helper.

Extracted rather than suppressed with a nolint: the duplication was
real, and the two call sites are the only places this shape appears.
Every error message is preserved verbatim, which is why the helper takes
both a plural and a singular noun.
This commit is contained in:
2026-08-09 13:43:09 +00:00
parent 90d5c1f73a
commit 3fa3c4ed19

View File

@@ -2,6 +2,7 @@ package imgcache
import ( import (
"context" "context"
"database/sql"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/fs" "io/fs"
@@ -647,32 +648,43 @@ func (c *Cache) reconcileVariantRows(ctx context.Context) error {
// allVariantKeys returns every tracked variant cache key. // allVariantKeys returns every tracked variant cache key.
func (c *Cache) allVariantKeys(ctx context.Context) ([]VariantKey, error) { func (c *Cache) allVariantKeys(ctx context.Context) ([]VariantKey, error) {
rows, err := c.db.QueryContext(ctx, `SELECT cache_key FROM variant_content`) return queryStringColumn[VariantKey](ctx, c.db,
`SELECT cache_key FROM variant_content`, "variant keys", "variant key")
}
// queryStringColumn runs a single-column query and returns the column
// values as T. plural names the set for the query and scan failure
// messages; singular names one row for the scan and iteration failure
// messages.
func queryStringColumn[T ~string](
ctx context.Context, db *sql.DB, query, plural, singular string,
) ([]T, error) {
rows, err := db.QueryContext(ctx, query)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to query variant keys: %w", err) return nil, fmt.Errorf("failed to query %s: %w", plural, err)
} }
defer func() { _ = rows.Close() }() defer func() { _ = rows.Close() }()
var keys []VariantKey var values []T
for rows.Next() { for rows.Next() {
var key string var value string
err := rows.Scan(&key) err := rows.Scan(&value)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to scan variant key: %w", err) return nil, fmt.Errorf("failed to scan %s: %w", singular, err)
} }
keys = append(keys, VariantKey(key)) values = append(values, T(value))
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
return nil, fmt.Errorf("variant key iteration failed: %w", err) return nil, fmt.Errorf("%s iteration failed: %w", singular, err)
} }
return keys, nil return values, nil
} }
// reconcileSourceFiles walks the source content directory, removing // reconcileSourceFiles walks the source content directory, removing
@@ -763,32 +775,9 @@ func (c *Cache) reconcileSourceRows(ctx context.Context) error {
// allSourceContentHashes returns every tracked source content hash. // allSourceContentHashes returns every tracked source content hash.
func (c *Cache) allSourceContentHashes(ctx context.Context) ([]ContentHash, error) { func (c *Cache) allSourceContentHashes(ctx context.Context) ([]ContentHash, error) {
rows, err := c.db.QueryContext(ctx, `SELECT content_hash FROM source_content`) return queryStringColumn[ContentHash](ctx, c.db,
if err != nil { `SELECT content_hash FROM source_content`,
return nil, fmt.Errorf("failed to query source content hashes: %w", err) "source content hashes", "content hash")
}
defer func() { _ = rows.Close() }()
var hashes []ContentHash
for rows.Next() {
var hash string
err := rows.Scan(&hash)
if err != nil {
return nil, fmt.Errorf("failed to scan content hash: %w", err)
}
hashes = append(hashes, ContentHash(hash))
}
err = rows.Err()
if err != nil {
return nil, fmt.Errorf("content hash iteration failed: %w", err)
}
return hashes, nil
} }
// sweepStaleTempFile removes a temp file left behind by a crashed // sweepStaleTempFile removes a temp file left behind by a crashed