feat(db): add artist_similarity_unmatched schema (migration 0012)
This commit is contained in:
@@ -216,6 +216,15 @@ type ArtistSimilarity struct {
|
|||||||
FetchedAt pgtype.Timestamptz
|
FetchedAt pgtype.Timestamptz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ArtistSimilarityUnmatched struct {
|
||||||
|
SeedArtistID pgtype.UUID
|
||||||
|
CandidateMbid string
|
||||||
|
CandidateName string
|
||||||
|
Score float64
|
||||||
|
Source string
|
||||||
|
FetchedAt pgtype.Timestamptz
|
||||||
|
}
|
||||||
|
|
||||||
type ContextualLike struct {
|
type ContextualLike struct {
|
||||||
ID pgtype.UUID
|
ID pgtype.UUID
|
||||||
UserID pgtype.UUID
|
UserID pgtype.UUID
|
||||||
|
|||||||
@@ -172,6 +172,38 @@ func (q *Queries) UpsertArtistSimilarity(ctx context.Context, arg UpsertArtistSi
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const upsertArtistSimilarityUnmatched = `-- name: UpsertArtistSimilarityUnmatched :exec
|
||||||
|
INSERT INTO artist_similarity_unmatched (
|
||||||
|
seed_artist_id, candidate_mbid, candidate_name, score, source
|
||||||
|
) VALUES ($1, $2, $3, $4, $5)
|
||||||
|
ON CONFLICT (seed_artist_id, candidate_mbid, source) DO UPDATE SET
|
||||||
|
candidate_name = EXCLUDED.candidate_name,
|
||||||
|
score = EXCLUDED.score,
|
||||||
|
fetched_at = now()
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpsertArtistSimilarityUnmatchedParams struct {
|
||||||
|
SeedArtistID pgtype.UUID
|
||||||
|
CandidateMbid string
|
||||||
|
CandidateName string
|
||||||
|
Score float64
|
||||||
|
Source string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persists an out-of-library similar-artist MBID. Idempotent on
|
||||||
|
// (seed_artist_id, candidate_mbid, source) — re-fetches refresh the
|
||||||
|
// name/score and bump fetched_at.
|
||||||
|
func (q *Queries) UpsertArtistSimilarityUnmatched(ctx context.Context, arg UpsertArtistSimilarityUnmatchedParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, upsertArtistSimilarityUnmatched,
|
||||||
|
arg.SeedArtistID,
|
||||||
|
arg.CandidateMbid,
|
||||||
|
arg.CandidateName,
|
||||||
|
arg.Score,
|
||||||
|
arg.Source,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const upsertTrackSimilarity = `-- name: UpsertTrackSimilarity :exec
|
const upsertTrackSimilarity = `-- name: UpsertTrackSimilarity :exec
|
||||||
INSERT INTO track_similarity (track_a_id, track_b_id, score, source, fetched_at)
|
INSERT INTO track_similarity (track_a_id, track_b_id, score, source, fetched_at)
|
||||||
VALUES ($1, $2, $3, 'listenbrainz', now())
|
VALUES ($1, $2, $3, 'listenbrainz', now())
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
DROP INDEX IF EXISTS artist_similarity_unmatched_seed_score_idx;
|
||||||
|
DROP TABLE IF EXISTS artist_similarity_unmatched;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- M5c: persist unmatched-similar-artist MBIDs that the M4b worker would
|
||||||
|
-- otherwise discard. Mirrors artist_similarity shape: same composite PK
|
||||||
|
-- with source, same (seed_id, score DESC) index, same source enum check.
|
||||||
|
-- The candidate side is text + name (no FK) — that's the whole point.
|
||||||
|
|
||||||
|
CREATE TABLE artist_similarity_unmatched (
|
||||||
|
seed_artist_id uuid NOT NULL REFERENCES artists(id) ON DELETE CASCADE,
|
||||||
|
candidate_mbid text NOT NULL,
|
||||||
|
candidate_name text NOT NULL,
|
||||||
|
score DOUBLE PRECISION NOT NULL,
|
||||||
|
source text NOT NULL CHECK (source IN ('listenbrainz', 'musicbrainz_tag', 'user_cooccurrence')),
|
||||||
|
fetched_at timestamptz NOT NULL DEFAULT now(),
|
||||||
|
PRIMARY KEY (seed_artist_id, candidate_mbid, source)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX artist_similarity_unmatched_seed_score_idx
|
||||||
|
ON artist_similarity_unmatched (seed_artist_id, score DESC);
|
||||||
@@ -48,3 +48,15 @@ INSERT INTO artist_similarity (artist_a_id, artist_b_id, score, source, fetched_
|
|||||||
VALUES ($1, $2, $3, 'listenbrainz', now())
|
VALUES ($1, $2, $3, 'listenbrainz', now())
|
||||||
ON CONFLICT (artist_a_id, artist_b_id, source)
|
ON CONFLICT (artist_a_id, artist_b_id, source)
|
||||||
DO UPDATE SET score = EXCLUDED.score, fetched_at = EXCLUDED.fetched_at;
|
DO UPDATE SET score = EXCLUDED.score, fetched_at = EXCLUDED.fetched_at;
|
||||||
|
|
||||||
|
-- name: UpsertArtistSimilarityUnmatched :exec
|
||||||
|
-- Persists an out-of-library similar-artist MBID. Idempotent on
|
||||||
|
-- (seed_artist_id, candidate_mbid, source) — re-fetches refresh the
|
||||||
|
-- name/score and bump fetched_at.
|
||||||
|
INSERT INTO artist_similarity_unmatched (
|
||||||
|
seed_artist_id, candidate_mbid, candidate_name, score, source
|
||||||
|
) VALUES ($1, $2, $3, $4, $5)
|
||||||
|
ON CONFLICT (seed_artist_id, candidate_mbid, source) DO UPDATE SET
|
||||||
|
candidate_name = EXCLUDED.candidate_name,
|
||||||
|
score = EXCLUDED.score,
|
||||||
|
fetched_at = now();
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ const TestUserPrefix = "test-"
|
|||||||
var dataTables = []string{
|
var dataTables = []string{
|
||||||
"artist_similarity",
|
"artist_similarity",
|
||||||
"track_similarity",
|
"track_similarity",
|
||||||
|
"artist_similarity_unmatched", // M5c
|
||||||
"scrobble_queue",
|
"scrobble_queue",
|
||||||
"contextual_likes",
|
"contextual_likes",
|
||||||
"general_likes_albums",
|
"general_likes_albums",
|
||||||
|
|||||||
Reference in New Issue
Block a user