Refactor size on disk calculation for track files

(cherry picked from commit 6c53bf30d52b9d10aa0f65c05cb6561cfbf3f8bd)
This commit is contained in:
Mark McDowall 2022-12-14 17:45:43 -08:00 committed by Bogdan
parent 0bcbf9df81
commit 241dda2b7e
2 changed files with 61 additions and 24 deletions

View File

@ -3,6 +3,7 @@ using System.Linq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.ArtistStats; using NzbDrone.Core.ArtistStats;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Music; using NzbDrone.Core.Music;
@ -124,5 +125,26 @@ namespace NzbDrone.Core.Test.ArtistStatsTests
stats.Should().HaveCount(1); stats.Should().HaveCount(1);
stats.First().SizeOnDisk.Should().Be(_trackFile.Size); stats.First().SizeOnDisk.Should().Be(_trackFile.Size);
} }
[Test]
public void should_not_duplicate_size_for_multi_track_files()
{
GivenTrackWithFile();
GivenTrack();
GivenTrackFile();
var track2 = _track.JsonClone();
track2.Id = 0;
track2.TrackNumber += 1;
track2.ForeignTrackId = "2";
Db.Insert(track2);
var stats = Subject.ArtistStatistics();
stats.Should().HaveCount(1);
stats.First().SizeOnDisk.Should().Be(_trackFile.Size);
}
} }
} }

View File

@ -16,7 +16,8 @@ namespace NzbDrone.Core.ArtistStats
public class ArtistStatisticsRepository : IArtistStatisticsRepository public class ArtistStatisticsRepository : IArtistStatisticsRepository
{ {
private const string _selectTemplate = "SELECT /**select**/ FROM \"Tracks\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/"; private const string _selectTracksTemplate = "SELECT /**select**/ FROM \"Tracks\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/";
private const string _selectTrackFilesTemplate = "SELECT /**select**/ FROM \"TrackFiles\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/";
private readonly IMainDatabase _database; private readonly IMainDatabase _database;
@ -28,32 +29,33 @@ namespace NzbDrone.Core.ArtistStats
public List<AlbumStatistics> ArtistStatistics() public List<AlbumStatistics> ArtistStatistics()
{ {
var time = DateTime.UtcNow; var time = DateTime.UtcNow;
return MapResults(Query(TracksBuilder(time), _selectTracksTemplate),
if (_database.DatabaseType == DatabaseType.PostgreSQL) Query(TrackFilesBuilder(), _selectTrackFilesTemplate));
{
return Query(Builder().WherePostgres<Album>(x => x.ReleaseDate < time));
}
return Query(Builder().Where<Album>(x => x.ReleaseDate < time));
} }
public List<AlbumStatistics> ArtistStatistics(int artistId) public List<AlbumStatistics> ArtistStatistics(int artistId)
{ {
var time = DateTime.UtcNow; var time = DateTime.UtcNow;
if (_database.DatabaseType == DatabaseType.PostgreSQL) return MapResults(Query(TracksBuilder(time).Where<Track>(x => x.ArtistMetadataId == artistId), _selectTracksTemplate),
{ Query(TrackFilesBuilder().Where<TrackFile>(x => x.Album.Value.ArtistMetadataId == artistId), _selectTrackFilesTemplate));
return Query(Builder().WherePostgres<Album>(x => x.ReleaseDate < time)
.WherePostgres<Artist>(x => x.Id == artistId));
} }
return Query(Builder().Where<Album>(x => x.ReleaseDate < time) private List<AlbumStatistics> MapResults(List<AlbumStatistics> tracksResult, List<AlbumStatistics> filesResult)
.Where<Artist>(x => x.Id == artistId)); {
tracksResult.ForEach(e =>
{
var file = filesResult.SingleOrDefault(f => f.ArtistId == e.ArtistId & f.AlbumId == e.AlbumId);
e.SizeOnDisk = file?.SizeOnDisk ?? 0;
});
return tracksResult;
} }
private List<AlbumStatistics> Query(SqlBuilder builder) private List<AlbumStatistics> Query(SqlBuilder builder, string template)
{ {
var sql = builder.AddTemplate(_selectTemplate).LogQuery(); var sql = builder.AddTemplate(template).LogQuery();
using (var conn = _database.OpenConnection()) using (var conn = _database.OpenConnection())
{ {
@ -61,25 +63,38 @@ namespace NzbDrone.Core.ArtistStats
} }
} }
private SqlBuilder Builder() private SqlBuilder TracksBuilder(DateTime currentDate)
{ {
var parameters = new DynamicParameters();
parameters.Add("currentDate", currentDate, null);
var trueIndicator = _database.DatabaseType == DatabaseType.PostgreSQL ? "true" : "1"; var trueIndicator = _database.DatabaseType == DatabaseType.PostgreSQL ? "true" : "1";
return new SqlBuilder(_database.DatabaseType) return new SqlBuilder(_database.DatabaseType)
.Select($@"""Artists"".""Id"" AS ""ArtistId"", .Select($@"""Artists"".""Id"" AS ""ArtistId"",
""Albums"".""Id"" AS ""AlbumId"", ""Albums"".""Id"" AS ""AlbumId"",
SUM(COALESCE(""TrackFiles"".""Size"", 0)) AS ""SizeOnDisk"",
COUNT(""Tracks"".""Id"") AS ""TotalTrackCount"", COUNT(""Tracks"".""Id"") AS ""TotalTrackCount"",
SUM(CASE WHEN ""Tracks"".""TrackFileId"" > 0 THEN 1 ELSE 0 END) AS ""AvailableTrackCount"", SUM(CASE WHEN ""Albums"".""ReleaseDate"" <= @currentDate OR ""Tracks"".""TrackFileId"" > 0 THEN 1 ELSE 0 END) AS ""AvailableTrackCount"",
SUM(CASE WHEN ""Albums"".""Monitored"" = {trueIndicator} OR ""Tracks"".""TrackFileId"" > 0 THEN 1 ELSE 0 END) AS ""TrackCount"", SUM(CASE WHEN (""Albums"".""Monitored"" = {trueIndicator} AND ""Albums"".""ReleaseDate"" <= @currentDate) OR ""Tracks"".""TrackFileId"" > 0 THEN 1 ELSE 0 END) AS ""TrackCount"",
SUM(CASE WHEN ""TrackFiles"".""Id"" IS NULL THEN 0 ELSE 1 END) AS ""TrackFileCount""") SUM(CASE WHEN ""Tracks"".""TrackFileId"" > 0 THEN 1 ELSE 0 END) AS TrackFileCount", parameters)
.Join<Track, AlbumRelease>((t, r) => t.AlbumReleaseId == r.Id) .Join<Track, AlbumRelease>((t, r) => t.AlbumReleaseId == r.Id)
.Join<AlbumRelease, Album>((r, a) => r.AlbumId == a.Id) .Join<AlbumRelease, Album>((r, a) => r.AlbumId == a.Id)
.Join<Album, Artist>((album, artist) => album.ArtistMetadataId == artist.ArtistMetadataId) .Join<Album, Artist>((album, artist) => album.ArtistMetadataId == artist.ArtistMetadataId)
.LeftJoin<Track, TrackFile>((t, f) => t.TrackFileId == f.Id)
.Where<AlbumRelease>(x => x.Monitored == true) .Where<AlbumRelease>(x => x.Monitored == true)
.GroupBy<Artist>(x => x.Id) .GroupBy<Artist>(x => x.Id)
.GroupBy<Album>(x => x.Id); .GroupBy<Album>(x => x.Id);
} }
private SqlBuilder TrackFilesBuilder()
{
return new SqlBuilder(_database.DatabaseType)
.Select(@"""Artists"".""Id"" AS ""ArtistId"",
""AlbumId"",
SUM(COALESCE(""Size"", 0)) AS SizeOnDisk")
.Join<TrackFile, Album>((t, a) => t.AlbumId == a.Id)
.Join<Album, Artist>((album, artist) => album.ArtistMetadataId == artist.ArtistMetadataId)
.GroupBy<Artist>(x => x.Id)
.GroupBy<TrackFile>(x => x.AlbumId);
}
} }
} }