// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 // source: fingerprints.sql package dbq import ( "context" "github.com/jackc/pgx/v5/pgtype" ) const deleteTrackFingerprint = `-- name: DeleteTrackFingerprint :exec DELETE FROM track_fingerprints WHERE track_id = $1 ` // A file changed but could not be fingerprinted, for a reason unrelated to the // file. The stored row describes the OLD bytes, so it goes and the backfill // re-derives it — nothing may keep trusting a stale identity. func (q *Queries) DeleteTrackFingerprint(ctx context.Context, trackID pgtype.UUID) error { _, err := q.db.Exec(ctx, deleteTrackFingerprint, trackID) return err } const getFingerprintCoverage = `-- name: GetFingerprintCoverage :one SELECT count(*)::bigint AS total, count(*) FILTER ( WHERE f.fingerprint_version >= $1 AND f.chromaprint_length_sec = $2 AND f.audio_stream_sha256 IS NOT NULL AND f.chromaprint IS NOT NULL )::bigint AS fingerprinted, count(*) FILTER ( WHERE f.fingerprint_version >= $1 AND f.chromaprint_length_sec = $2 AND (f.audio_stream_sha256 IS NULL OR f.chromaprint IS NULL) )::bigint AS rejected, count(*) FILTER ( WHERE f.track_id IS NULL OR f.fingerprint_version < $1 OR f.chromaprint_length_sec <> $2 )::bigint AS pending FROM tracks t LEFT JOIN track_fingerprints f ON f.track_id = t.id WHERE t.missing_since IS NULL ` type GetFingerprintCoverageParams struct { CurrentVersion int16 ChromaprintLengthSec int32 } type GetFingerprintCoverageRow struct { Total int64 Fingerprinted int64 Rejected int64 Pending int64 } // The admin gauge for the backfill. fingerprinted + rejected + pending = total. // "Current" means derived by the current method AT the current length: a row at // another length is pending, because the backfill will re-derive it. rejected is // a current row with a NULL half: a tool ran and refused the file, which is // settled rather than waiting. Missing tracks are excluded, or the gauge could // never reach the end. func (q *Queries) GetFingerprintCoverage(ctx context.Context, arg GetFingerprintCoverageParams) (GetFingerprintCoverageRow, error) { row := q.db.QueryRow(ctx, getFingerprintCoverage, arg.CurrentVersion, arg.ChromaprintLengthSec) var i GetFingerprintCoverageRow err := row.Scan( &i.Total, &i.Fingerprinted, &i.Rejected, &i.Pending, ) return i, err } const listTracksNeedingFingerprint = `-- name: ListTracksNeedingFingerprint :many SELECT t.id, t.file_path FROM tracks t LEFT JOIN track_fingerprints f ON f.track_id = t.id WHERE t.missing_since IS NULL -- A row taken at another length is as stale as one from an older method: -- chromaprints at two lengths cannot be compared (#3913). AND (f.track_id IS NULL OR f.fingerprint_version < $1 OR f.chromaprint_length_sec <> $2) AND t.id > $3 ORDER BY t.id LIMIT $4 ` type ListTracksNeedingFingerprintParams struct { CurrentVersion int16 ChromaprintLengthSec int32 AfterID pgtype.UUID BatchLimit int32 } type ListTracksNeedingFingerprintRow struct { ID pgtype.UUID FilePath string } // The backfill's work queue (#3908): tracks with no fingerprint, or one derived // by an older method. Keyset-paged on id so a pass visits each track at most // once. That cursor is load-bearing: an inconclusive attempt writes no row, so // without it a file that keeps timing out would be listed again straight away // and retried in a tight loop. Missing tracks are skipped — there is no file to // read. func (q *Queries) ListTracksNeedingFingerprint(ctx context.Context, arg ListTracksNeedingFingerprintParams) ([]ListTracksNeedingFingerprintRow, error) { rows, err := q.db.Query(ctx, listTracksNeedingFingerprint, arg.CurrentVersion, arg.ChromaprintLengthSec, arg.AfterID, arg.BatchLimit, ) if err != nil { return nil, err } defer rows.Close() var items []ListTracksNeedingFingerprintRow for rows.Next() { var i ListTracksNeedingFingerprintRow if err := rows.Scan(&i.ID, &i.FilePath); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const upsertTrackFingerprint = `-- name: UpsertTrackFingerprint :exec INSERT INTO track_fingerprints ( track_id, audio_stream_sha256, chromaprint, fingerprint_version, chromaprint_length_sec ) VALUES ( $1, $2, $3, $4, $5 ) ON CONFLICT (track_id) DO UPDATE SET audio_stream_sha256 = EXCLUDED.audio_stream_sha256, chromaprint = EXCLUDED.chromaprint, fingerprint_version = EXCLUDED.fingerprint_version, chromaprint_length_sec = EXCLUDED.chromaprint_length_sec, computed_at = now() ` type UpsertTrackFingerprintParams struct { TrackID pgtype.UUID AudioStreamSha256 []byte Chromaprint []int32 FingerprintVersion int16 ChromaprintLengthSec int32 } // Written whenever a track's fingerprint is derived: by the scan when a file is // new or its bytes changed, and by the backfill (#3908) for rows derived by an // older method. Replaces the row wholesale — a fingerprint of the old bytes has // no standing once the file has changed. func (q *Queries) UpsertTrackFingerprint(ctx context.Context, arg UpsertTrackFingerprintParams) error { _, err := q.db.Exec(ctx, upsertTrackFingerprint, arg.TrackID, arg.AudioStreamSha256, arg.Chromaprint, arg.FingerprintVersion, arg.ChromaprintLengthSec, ) return err }