fix(db): apply sqlc's actual output for candidate_artist_tags — #2376
Three divergences in the hand-written generated file, all caught by
verify-generate on the first run. Two are sqlc rules I had wrong:
1. When a query's SELECT list exactly matches a table's columns in order,
sqlc REUSES the model struct rather than emitting a bespoke Row type.
So ListCandidateArtistTagsForMbids returns []CandidateArtistTag, and
ListCandidateArtistTagsForMbidsRow should never have existed.
2. models.go is ordered by GO STRUCT NAME, not table name. Table order
would put candidate_artist_tag_state before candidate_artist_tags;
sqlc emits CandidateArtistTag before CandidateArtistTagState. The
earlier slice-3 observation ("ordered by table name") was consistent
with both orderings and so never discriminated — this case does.
3. sqlc smart-quotes a doubled '' inside a promoted comment into a
typographic ”. Reworded the prose to say "the empty string" instead of
encoding a mangling into the source.
Note the integration lane PASSED on the broken push while this failed.
That is #2380's lesson landing again, and the reason the check exists:
valid SQL executing against real Postgres proves nothing about whether
the committed Go matches its source.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -110,23 +110,17 @@ SELECT candidate_mbid, tag, weight
|
|||||||
WHERE candidate_mbid = ANY($1::text[])
|
WHERE candidate_mbid = ANY($1::text[])
|
||||||
`
|
`
|
||||||
|
|
||||||
type ListCandidateArtistTagsForMbidsRow struct {
|
|
||||||
CandidateMbid string
|
|
||||||
Tag string
|
|
||||||
Weight float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cached tags for a set of candidates, for slice 6's taste-overlap ranking.
|
// Cached tags for a set of candidates, for slice 6's taste-overlap ranking.
|
||||||
// One row per (candidate, tag).
|
// One row per (candidate, tag).
|
||||||
func (q *Queries) ListCandidateArtistTagsForMbids(ctx context.Context, dollar_1 []string) ([]ListCandidateArtistTagsForMbidsRow, error) {
|
func (q *Queries) ListCandidateArtistTagsForMbids(ctx context.Context, dollar_1 []string) ([]CandidateArtistTag, error) {
|
||||||
rows, err := q.db.Query(ctx, listCandidateArtistTagsForMbids, dollar_1)
|
rows, err := q.db.Query(ctx, listCandidateArtistTagsForMbids, dollar_1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []ListCandidateArtistTagsForMbidsRow
|
var items []CandidateArtistTag
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i ListCandidateArtistTagsForMbidsRow
|
var i CandidateArtistTag
|
||||||
if err := rows.Scan(&i.CandidateMbid, &i.Tag, &i.Weight); err != nil {
|
if err := rows.Scan(&i.CandidateMbid, &i.Tag, &i.Weight); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -186,10 +180,11 @@ type ListCandidateArtistsMissingTagsRow struct {
|
|||||||
// Already-in-library candidates are skipped: they have an artists row, so
|
// Already-in-library candidates are skipped: they have an artists row, so
|
||||||
// their tags belong in track_tags, and the suggestion query filters them out
|
// their tags belong in track_tags, and the suggestion query filters them out
|
||||||
// anyway. $1 = current tag_sources_version, $2 = limit.
|
// anyway. $1 = current tag_sources_version, $2 = limit.
|
||||||
// candidate_name is coalesced to '' so it lands non-nullable in Go: the name is
|
// candidate_name is coalesced to the empty string so it lands non-nullable in
|
||||||
// only a Last.fm lookup key, and empty simply means "MBID-keyed providers only",
|
// Go: the name is only a Last.fm lookup key, and empty simply means "MBID-keyed
|
||||||
// which the provider chain already handles. max() is an arbitrary-but-
|
// providers only", which the provider chain already handles. max() is an
|
||||||
// deterministic pick when several seeds spell the same MBID differently.
|
// arbitrary-but-deterministic pick when several seeds spell one MBID
|
||||||
|
// differently.
|
||||||
func (q *Queries) ListCandidateArtistsMissingTags(ctx context.Context, arg ListCandidateArtistsMissingTagsParams) ([]ListCandidateArtistsMissingTagsRow, error) {
|
func (q *Queries) ListCandidateArtistsMissingTags(ctx context.Context, arg ListCandidateArtistsMissingTagsParams) ([]ListCandidateArtistsMissingTagsRow, error) {
|
||||||
rows, err := q.db.Query(ctx, listCandidateArtistsMissingTags, arg.TagSourcesVersion, arg.Limit)
|
rows, err := q.db.Query(ctx, listCandidateArtistsMissingTags, arg.TagSourcesVersion, arg.Limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -240,6 +240,12 @@ type AuditLog struct {
|
|||||||
CreatedAt pgtype.Timestamptz
|
CreatedAt pgtype.Timestamptz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CandidateArtistTag struct {
|
||||||
|
CandidateMbid string
|
||||||
|
Tag string
|
||||||
|
Weight float64
|
||||||
|
}
|
||||||
|
|
||||||
type CandidateArtistTagState struct {
|
type CandidateArtistTagState struct {
|
||||||
CandidateMbid string
|
CandidateMbid string
|
||||||
TagSource string
|
TagSource string
|
||||||
@@ -247,12 +253,6 @@ type CandidateArtistTagState struct {
|
|||||||
UpdatedAt pgtype.Timestamptz
|
UpdatedAt pgtype.Timestamptz
|
||||||
}
|
}
|
||||||
|
|
||||||
type CandidateArtistTag struct {
|
|
||||||
CandidateMbid string
|
|
||||||
Tag string
|
|
||||||
Weight float64
|
|
||||||
}
|
|
||||||
|
|
||||||
type ContextualLike struct {
|
type ContextualLike struct {
|
||||||
ID pgtype.UUID
|
ID pgtype.UUID
|
||||||
UserID pgtype.UUID
|
UserID pgtype.UUID
|
||||||
|
|||||||
@@ -20,10 +20,11 @@
|
|||||||
-- Already-in-library candidates are skipped: they have an artists row, so
|
-- Already-in-library candidates are skipped: they have an artists row, so
|
||||||
-- their tags belong in track_tags, and the suggestion query filters them out
|
-- their tags belong in track_tags, and the suggestion query filters them out
|
||||||
-- anyway. $1 = current tag_sources_version, $2 = limit.
|
-- anyway. $1 = current tag_sources_version, $2 = limit.
|
||||||
-- candidate_name is coalesced to '' so it lands non-nullable in Go: the name is
|
-- candidate_name is coalesced to the empty string so it lands non-nullable in
|
||||||
-- only a Last.fm lookup key, and empty simply means "MBID-keyed providers only",
|
-- Go: the name is only a Last.fm lookup key, and empty simply means "MBID-keyed
|
||||||
-- which the provider chain already handles. max() is an arbitrary-but-
|
-- providers only", which the provider chain already handles. max() is an
|
||||||
-- deterministic pick when several seeds spell the same MBID differently.
|
-- arbitrary-but-deterministic pick when several seeds spell one MBID
|
||||||
|
-- differently.
|
||||||
SELECT u.candidate_mbid,
|
SELECT u.candidate_mbid,
|
||||||
coalesce(max(u.candidate_name), '')::text AS candidate_name,
|
coalesce(max(u.candidate_name), '')::text AS candidate_name,
|
||||||
sum(u.score)::float8 AS total_score
|
sum(u.score)::float8 AS total_score
|
||||||
|
|||||||
Reference in New Issue
Block a user