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:
@@ -356,8 +356,12 @@ defmodule MusicLibrary.ListeningStats do
|
|||||||
'cover_hash', r.cover_hash\
|
'cover_hash', r.cover_hash\
|
||||||
)) \
|
)) \
|
||||||
FROM records r \
|
FROM records r \
|
||||||
JOIN record_releases rr ON rr.record_id = r.id \
|
WHERE r.musicbrainz_id = (\
|
||||||
WHERE rr.release_id = (? ->> '$.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
|
t.album
|
||||||
),
|
),
|
||||||
@@ -365,8 +369,10 @@ defmodule MusicLibrary.ListeningStats do
|
|||||||
fragment(
|
fragment(
|
||||||
"""
|
"""
|
||||||
(SELECT min(ar.musicbrainz_id) FROM artist_records ar \
|
(SELECT min(ar.musicbrainz_id) FROM artist_records ar \
|
||||||
WHERE ar.record_id = (\
|
INNER JOIN records r ON r.id = ar.record_id \
|
||||||
SELECT rr.record_id FROM record_releases rr \
|
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') \
|
WHERE rr.release_id = (? ->> '$.musicbrainz_id') \
|
||||||
LIMIT 1\
|
LIMIT 1\
|
||||||
))\
|
))\
|
||||||
@@ -377,10 +383,13 @@ defmodule MusicLibrary.ListeningStats do
|
|||||||
fragment(
|
fragment(
|
||||||
"""
|
"""
|
||||||
(SELECT r.cover_hash FROM records r \
|
(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') \
|
WHERE rr.release_id = (? ->> '$.musicbrainz_id') \
|
||||||
AND r.purchased_at IS NOT NULL \
|
LIMIT 1\
|
||||||
ORDER BY r.id \
|
) \
|
||||||
|
ORDER BY (CASE WHEN r.purchased_at IS NOT NULL THEN 0 ELSE 1 END), r.id \
|
||||||
LIMIT 1)\
|
LIMIT 1)\
|
||||||
""",
|
""",
|
||||||
t.album
|
t.album
|
||||||
|
|||||||
@@ -335,16 +335,28 @@ defmodule MusicLibrary.ListeningStatsTest do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "deduplication when multiple records share release IDs" do
|
describe "deduplication when multiple records share a release group" do
|
||||||
setup do
|
setup do
|
||||||
# Create two collected records that share the same MusicBrainz release IDs
|
# Create two collected records that share the same release group
|
||||||
# (both use the default marbles fixture with identical musicbrainz_data).
|
# (musicbrainz_id) but may have different physical release IDs.
|
||||||
# This produces two rows per release_id in record_releases, which previously
|
# The matching_records query groups by release group, so both records
|
||||||
# caused fan-out in ListeningStats joins.
|
# should appear for any scrobble matching either record's release IDs.
|
||||||
record_a = RecordsFixtures.record(%{title: "Marbles Copy A"})
|
shared_musicbrainz_id = Ecto.UUID.generate()
|
||||||
record_b = RecordsFixtures.record(%{title: "Marbles Copy B"})
|
|
||||||
|
|
||||||
# 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"
|
shared_release_id = "d3f9b9e2-73f5-4b47-a2a7-2c2199aad608"
|
||||||
now = System.system_time(:second)
|
now = System.system_time(:second)
|
||||||
|
|
||||||
@@ -364,10 +376,11 @@ defmodule MusicLibrary.ListeningStatsTest do
|
|||||||
scrobbled_at_uts: now - 200
|
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])
|
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,
|
expected_record_id: expected_record_id,
|
||||||
shared_release_id: shared_release_id
|
shared_release_id: shared_release_id
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user