using System; using System.Collections.Generic; using System.Linq; using Dapper; using NzbDrone.Core.Datastore; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Music; namespace NzbDrone.Core.ArtistStats { public interface IArtistStatisticsRepository { List ArtistStatistics(); List ArtistStatistics(int artistId); } public class ArtistStatisticsRepository : IArtistStatisticsRepository { 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; public ArtistStatisticsRepository(IMainDatabase database) { _database = database; } public List ArtistStatistics() { var time = DateTime.UtcNow; return MapResults(Query(TracksBuilder(time), _selectTracksTemplate), Query(TrackFilesBuilder(), _selectTrackFilesTemplate)); } public List ArtistStatistics(int artistId) { var time = DateTime.UtcNow; return MapResults(Query(TracksBuilder(time).Where(x => x.ArtistMetadataId == artistId), _selectTracksTemplate), Query(TrackFilesBuilder().Where(x => x.Album.Value.ArtistMetadataId == artistId), _selectTrackFilesTemplate)); } private List MapResults(List tracksResult, List filesResult) { 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 Query(SqlBuilder builder, string template) { var sql = builder.AddTemplate(template).LogQuery(); using (var conn = _database.OpenConnection()) { return conn.Query(sql.RawSql, sql.Parameters).ToList(); } } private SqlBuilder TracksBuilder(DateTime currentDate) { var parameters = new DynamicParameters(); parameters.Add("currentDate", currentDate, null); var trueIndicator = _database.DatabaseType == DatabaseType.PostgreSQL ? "true" : "1"; return new SqlBuilder(_database.DatabaseType) .Select($@"""Artists"".""Id"" AS ""ArtistId"", ""Albums"".""Id"" AS ""AlbumId"", COUNT(""Tracks"".""Id"") AS ""TotalTrackCount"", SUM(CASE WHEN ""Albums"".""ReleaseDate"" <= @currentDate OR ""Tracks"".""TrackFileId"" > 0 THEN 1 ELSE 0 END) AS ""AvailableTrackCount"", SUM(CASE WHEN (""Albums"".""Monitored"" = {trueIndicator} AND ""Albums"".""ReleaseDate"" <= @currentDate) OR ""Tracks"".""TrackFileId"" > 0 THEN 1 ELSE 0 END) AS ""TrackCount"", SUM(CASE WHEN ""Tracks"".""TrackFileId"" > 0 THEN 1 ELSE 0 END) AS TrackFileCount", parameters) .Join((t, r) => t.AlbumReleaseId == r.Id) .Join((r, a) => r.AlbumId == a.Id) .Join((album, artist) => album.ArtistMetadataId == artist.ArtistMetadataId) .Where(x => x.Monitored == true) .GroupBy(x => x.Id) .GroupBy(x => x.Id); } private SqlBuilder TrackFilesBuilder() { return new SqlBuilder(_database.DatabaseType) .Select(@"""Artists"".""Id"" AS ""ArtistId"", ""AlbumId"", SUM(COALESCE(""Size"", 0)) AS SizeOnDisk") .Join((t, a) => t.AlbumId == a.Id) .Join((album, artist) => album.ArtistMetadataId == artist.ArtistMetadataId) .GroupBy(x => x.Id) .GroupBy(x => x.AlbumId); } } }