refactor: extract queryStringColumn helper for the accounting queries (dupl)
All checks were successful
check / check (push) Successful in 2m23s
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:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user