Return matching_records list from tracks_with_record_info_query

Replace scalar collected_record_id/wishlisted_record_id subqueries with
a single matching_records JSON array grouped by release group
(records.musicbrainz_id). Add parse_matching_records/1 for JSON parsing
and derive_legacy_record_ids/2 as a temporary bridge for existing
templates. Update tests to use shared musicbrainz_id fixtures.
This commit is contained in:
Claudio Ortolina
2026-04-14 14:17:02 +01:00
parent 9f4135661e
commit cfd267627c
2 changed files with 38 additions and 16 deletions
+16 -7
View File
@@ -356,8 +356,12 @@ defmodule MusicLibrary.ListeningStats do
'cover_hash', r.cover_hash\
)) \
FROM records r \
JOIN record_releases rr ON rr.record_id = r.id \
WHERE rr.release_id = (? ->> '$.musicbrainz_id'))\
WHERE r.musicbrainz_id = (\
SELECT r2.musicbrainz_id FROM records r2 \
INNER JOIN record_releases rr ON rr.record_id = r2.id \
WHERE rr.release_id = (? ->> '$.musicbrainz_id') \
LIMIT 1\
))\
""",
t.album
),
@@ -365,8 +369,10 @@ defmodule MusicLibrary.ListeningStats do
fragment(
"""
(SELECT min(ar.musicbrainz_id) FROM artist_records ar \
WHERE ar.record_id = (\
SELECT rr.record_id FROM record_releases rr \
INNER JOIN records r ON r.id = ar.record_id \
WHERE r.musicbrainz_id = (\
SELECT r2.musicbrainz_id FROM records r2 \
INNER JOIN record_releases rr ON rr.record_id = r2.id \
WHERE rr.release_id = (? ->> '$.musicbrainz_id') \
LIMIT 1\
))\
@@ -377,10 +383,13 @@ defmodule MusicLibrary.ListeningStats do
fragment(
"""
(SELECT r.cover_hash FROM records r \
JOIN record_releases rr ON rr.record_id = r.id \
WHERE r.musicbrainz_id = (\
SELECT r2.musicbrainz_id FROM records r2 \
INNER JOIN record_releases rr ON rr.record_id = r2.id \
WHERE rr.release_id = (? ->> '$.musicbrainz_id') \
AND r.purchased_at IS NOT NULL \
ORDER BY r.id \
LIMIT 1\
) \
ORDER BY (CASE WHEN r.purchased_at IS NOT NULL THEN 0 ELSE 1 END), r.id \
LIMIT 1)\
""",
t.album
+22 -9
View File
@@ -335,16 +335,28 @@ defmodule MusicLibrary.ListeningStatsTest do
end
end
describe "deduplication when multiple records share release IDs" do
describe "deduplication when multiple records share a release group" do
setup do
# Create two collected records that share the same MusicBrainz release IDs
# (both use the default marbles fixture with identical musicbrainz_data).
# This produces two rows per release_id in record_releases, which previously
# caused fan-out in ListeningStats joins.
record_a = RecordsFixtures.record(%{title: "Marbles Copy A"})
record_b = RecordsFixtures.record(%{title: "Marbles Copy B"})
# Create two collected records that share the same release group
# (musicbrainz_id) but may have different physical release IDs.
# The matching_records query groups by release group, so both records
# should appear for any scrobble matching either record's release IDs.
shared_musicbrainz_id = Ecto.UUID.generate()
# Pick a release_id shared by both records
record_a =
RecordsFixtures.record(%{
title: "Marbles Copy A",
musicbrainz_id: shared_musicbrainz_id
})
record_b =
RecordsFixtures.record(%{
title: "Marbles Copy B",
musicbrainz_id: shared_musicbrainz_id
})
# Pick a release_id from the marbles fixture (shared by both records
# since they use the same musicbrainz_data)
shared_release_id = "d3f9b9e2-73f5-4b47-a2a7-2c2199aad608"
now = System.system_time(:second)
@@ -364,10 +376,11 @@ defmodule MusicLibrary.ListeningStatsTest do
scrobbled_at_uts: now - 200
})
# The lexicographically smaller record_id should consistently win (MIN)
expected_record_id = Enum.min([record_a.id, record_b.id])
%{
record_a: record_a,
record_b: record_b,
expected_record_id: expected_record_id,
shared_release_id: shared_release_id
}