From 86ab26e2d9bb0bbfae0971176dd34d507634080f Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 19 Jun 2011 20:08:09 -0700 Subject: [PATCH 1/6] UpcomingProvider now gets Series in call for episodes. --- .../Providers/UpcomingEpisodesProvider.cs | 22 +++- NzbDrone.Core/Repository/Episode.cs | 2 +- .../Controllers/UpcomingController.cs | 112 +++++++----------- 3 files changed, 57 insertions(+), 79 deletions(-) diff --git a/NzbDrone.Core/Providers/UpcomingEpisodesProvider.cs b/NzbDrone.Core/Providers/UpcomingEpisodesProvider.cs index 2b0d9c9f1..423f33947 100644 --- a/NzbDrone.Core/Providers/UpcomingEpisodesProvider.cs +++ b/NzbDrone.Core/Providers/UpcomingEpisodesProvider.cs @@ -20,8 +20,10 @@ namespace NzbDrone.Core.Providers public virtual UpcomingEpisodesModel Upcoming() { - var allEps = _database.Fetch("WHERE AirDate BETWEEN @0 AND @1", DateTime.Today.AddDays(-1), - DateTime.Today.AddDays(8)); + var allEps = _database.Fetch(@"SELECT * FROM Episodes + INNER JOIN Series ON Episodes.SeriesId = Series.SeriesId + WHERE AirDate BETWEEN @0 AND @1", + DateTime.Today.AddDays(-1), DateTime.Today.AddDays(8)); var yesterday = allEps.Where(e => e.AirDate == DateTime.Today.AddDays(-1)).ToList(); var today = allEps.Where(e => e.AirDate == DateTime.Today).ToList(); @@ -32,22 +34,30 @@ namespace NzbDrone.Core.Providers public virtual List Yesterday() { - return _database.Fetch("WHERE AirDate = @0", DateTime.Today.AddDays(-1)); + return _database.Fetch(@"SELECT * FROM Episodes + INNER JOIN Series ON Episodes.SeriesId = Series.SeriesId + WHERE AirDate = @0", DateTime.Today.AddDays(-1)); } public virtual List Today() { - return _database.Fetch("WHERE AirDate = @0", DateTime.Today); + return _database.Fetch(@"SELECT * FROM Episodes + INNER JOIN Series ON Episodes.SeriesId = Series.SeriesId + WHERE AirDate = @0", DateTime.Today); } public virtual List Tomorrow() { - return _database.Fetch("WHERE AirDate = @0", DateTime.Today.AddDays(1)); + return _database.Fetch(@"SELECT * FROM Episodes + INNER JOIN Series ON Episodes.SeriesId = Series.SeriesId + WHERE AirDate = @0", DateTime.Today.AddDays(1)); } public virtual List Week() { - return _database.Fetch("WHERE AirDate BETWEEN @0 AND @1", DateTime.Today.AddDays(2), DateTime.Today.AddDays(8)); + return _database.Fetch(@"SELECT * FROM Episodes + INNER JOIN Series ON Episodes.SeriesId = Series.SeriesId + WHERE AirDate BETWEEN @0 AND @1", DateTime.Today.AddDays(2), DateTime.Today.AddDays(8)); } } } \ No newline at end of file diff --git a/NzbDrone.Core/Repository/Episode.cs b/NzbDrone.Core/Repository/Episode.cs index 6e482e2ec..f5ce16816 100644 --- a/NzbDrone.Core/Repository/Episode.cs +++ b/NzbDrone.Core/Repository/Episode.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Repository /// public DateTime? GrabDate { get; set; } - [Ignore] + [ResultColumn] public EpisodeStatusType Status { get diff --git a/NzbDrone.Web/Controllers/UpcomingController.cs b/NzbDrone.Web/Controllers/UpcomingController.cs index d5c02f4a4..3ca9d69e6 100644 --- a/NzbDrone.Web/Controllers/UpcomingController.cs +++ b/NzbDrone.Web/Controllers/UpcomingController.cs @@ -30,25 +30,17 @@ namespace NzbDrone.Web.Controllers [GridAction] public ActionResult _AjaxBindingYesterday() { - var upcomingDb = _upcomingEpisodesProvider.Yesterday(); - var upcoming = new List(); - - foreach (var item in upcomingDb) + var upcoming = _upcomingEpisodesProvider.Yesterday().Select(u => new UpcomingEpisodeModel { - var series = _seriesProvider.GetSeries(item.SeriesId); - - upcoming.Add(new UpcomingEpisodeModel - { - SeriesId = series.SeriesId, - EpisodeId = item.EpisodeId, - SeriesName = series.Title, - SeasonNumber = item.SeasonNumber, - EpisodeNumber = item.EpisodeNumber, - Title = item.Title, - Overview = item.Overview, - AirDate = item.AirDate.Add(Convert.ToDateTime(series.AirTimes).TimeOfDay) - }); - } + SeriesId = u.Series.SeriesId, + EpisodeId = u.EpisodeId, + SeriesName = u.Series.Title, + SeasonNumber = u.SeasonNumber, + EpisodeNumber = u.EpisodeNumber, + Title = u.Title, + Overview = u.Overview, + AirDate = u.AirDate.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay) + }); return View(new GridModel(upcoming)); } @@ -56,25 +48,17 @@ namespace NzbDrone.Web.Controllers [GridAction] public ActionResult _AjaxBindingToday() { - var upcomingDb = _upcomingEpisodesProvider.Today(); - var upcoming = new List(); - - foreach (var item in upcomingDb) + var upcoming = _upcomingEpisodesProvider.Today().Select(u => new UpcomingEpisodeModel { - var series = _seriesProvider.GetSeries(item.SeriesId); - - upcoming.Add(new UpcomingEpisodeModel - { - SeriesId = series.SeriesId, - EpisodeId = item.EpisodeId, - SeriesName = series.Title, - SeasonNumber = item.SeasonNumber, - EpisodeNumber = item.EpisodeNumber, - Title = item.Title, - Overview = item.Overview, - AirDate = item.AirDate.Add(Convert.ToDateTime(series.AirTimes).TimeOfDay) - }); - } + SeriesId = u.Series.SeriesId, + EpisodeId = u.EpisodeId, + SeriesName = u.Series.Title, + SeasonNumber = u.SeasonNumber, + EpisodeNumber = u.EpisodeNumber, + Title = u.Title, + Overview = u.Overview, + AirDate = u.AirDate.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay) + }); return View(new GridModel(upcoming)); } @@ -82,25 +66,17 @@ namespace NzbDrone.Web.Controllers [GridAction] public ActionResult _AjaxBindingTomorrow() { - var upcomingDb = _upcomingEpisodesProvider.Tomorrow(); - var upcoming = new List(); - - foreach (var item in upcomingDb) + var upcoming = _upcomingEpisodesProvider.Tomorrow().Select(u => new UpcomingEpisodeModel { - var series = _seriesProvider.GetSeries(item.SeriesId); - - upcoming.Add(new UpcomingEpisodeModel - { - SeriesId = series.SeriesId, - EpisodeId = item.EpisodeId, - SeriesName = series.Title, - SeasonNumber = item.SeasonNumber, - EpisodeNumber = item.EpisodeNumber, - Title = item.Title, - Overview = item.Overview, - AirDate = item.AirDate.Add(Convert.ToDateTime(series.AirTimes).TimeOfDay) - }); - } + SeriesId = u.Series.SeriesId, + EpisodeId = u.EpisodeId, + SeriesName = u.Series.Title, + SeasonNumber = u.SeasonNumber, + EpisodeNumber = u.EpisodeNumber, + Title = u.Title, + Overview = u.Overview, + AirDate = u.AirDate.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay) + }); return View(new GridModel(upcoming)); } @@ -108,25 +84,17 @@ namespace NzbDrone.Web.Controllers [GridAction] public ActionResult _AjaxBindingWeek() { - var upcomingDb = _upcomingEpisodesProvider.Week(); - var upcoming = new List(); - - foreach (var item in upcomingDb) + var upcoming = _upcomingEpisodesProvider.Week().Select(u => new UpcomingEpisodeModel { - var series = _seriesProvider.GetSeries(item.SeriesId); - - upcoming.Add(new UpcomingEpisodeModel - { - SeriesId = series.SeriesId, - EpisodeId = item.EpisodeId, - SeriesName = series.Title, - SeasonNumber = item.SeasonNumber, - EpisodeNumber = item.EpisodeNumber, - Title = item.Title, - Overview = item.Overview, - AirDate = item.AirDate.Add(Convert.ToDateTime(series.AirTimes).TimeOfDay) - }); - } + SeriesId = u.Series.SeriesId, + EpisodeId = u.EpisodeId, + SeriesName = u.Series.Title, + SeasonNumber = u.SeasonNumber, + EpisodeNumber = u.EpisodeNumber, + Title = u.Title, + Overview = u.Overview, + AirDate = u.AirDate.Add(Convert.ToDateTime(u.Series.AirTimes).TimeOfDay) + }); return View(new GridModel(upcoming)); } From 5a99d374d99f58d2d449321c364788cdc5c1e4de Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 19 Jun 2011 20:21:54 -0700 Subject: [PATCH 2/6] Updated tests to for Upcoming Provider to make sure a series is returned. --- .../UpcomingEpisodesProviderTest.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/NzbDrone.Core.Test/UpcomingEpisodesProviderTest.cs b/NzbDrone.Core.Test/UpcomingEpisodesProviderTest.cs index fdd982e83..3e862686b 100644 --- a/NzbDrone.Core.Test/UpcomingEpisodesProviderTest.cs +++ b/NzbDrone.Core.Test/UpcomingEpisodesProviderTest.cs @@ -1,7 +1,9 @@ // ReSharper disable RedundantUsingDirective using System; +using System.Collections.Generic; using AutoMoq; using FizzWare.NBuilder; +using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Providers; using NzbDrone.Core.Repository; @@ -18,6 +20,7 @@ namespace NzbDrone.Core.Test private Episode tomorrow; private Episode twoDays; private Episode sevenDays; + private Series series; [SetUp] public new void Setup() @@ -25,33 +28,41 @@ namespace NzbDrone.Core.Test yesterday = Builder.CreateNew() .With(c => c.AirDate = DateTime.Today.AddDays(-1)) .With(c => c.Title = "Yesterday") + .With(c => c.SeriesId = 1) .Build(); today = Builder.CreateNew() .With(c => c.AirDate = DateTime.Today) .With(c => c.Title = "Today") + .With(c => c.SeriesId = 1) .Build(); tomorrow = Builder.CreateNew() .With(c => c.AirDate = DateTime.Today.AddDays(1)) .With(c => c.Title = "Tomorrow") + .With(c => c.SeriesId = 1) .Build(); twoDays = Builder.CreateNew() .With(c => c.AirDate = DateTime.Today.AddDays(2)) .With(c => c.Title = "Two Days") + .With(c => c.SeriesId = 1) .Build(); sevenDays = Builder.CreateNew() .With(c => c.AirDate = DateTime.Today.AddDays(7)) .With(c => c.Title = "Seven Days") + .With(c => c.SeriesId = 1) .Build(); sevenDays = Builder.CreateNew() .With(c => c.AirDate = DateTime.Today.AddDays(8)) .With(c => c.Title = "Eight Days") + .With(c => c.SeriesId = 1) .Build(); + series = Builder.CreateNew().With(s => s.SeriesId = 1).Build(); + base.Setup(); } @@ -68,6 +79,7 @@ namespace NzbDrone.Core.Test database.Insert(tomorrow); database.Insert(twoDays); database.Insert(sevenDays); + database.Insert(series); //Act var result = mocker.Resolve().Yesterday(); @@ -75,6 +87,8 @@ namespace NzbDrone.Core.Test //Assert Assert.AreEqual(1, result.Count); Assert.AreEqual(yesterday.Title, result[0].Title); + result[0].Series.Should().NotBeNull(); + result[0].Series.SeriesId.Should().NotBe(0); } [Test] @@ -90,6 +104,7 @@ namespace NzbDrone.Core.Test database.Insert(tomorrow); database.Insert(twoDays); database.Insert(sevenDays); + database.Insert(series); //Act var result = mocker.Resolve().Today(); @@ -97,6 +112,8 @@ namespace NzbDrone.Core.Test //Assert Assert.AreEqual(1, result.Count); Assert.AreEqual(today.Title, result[0].Title); + result[0].Series.Should().NotBeNull(); + result[0].Series.SeriesId.Should().NotBe(0); } [Test] @@ -112,6 +129,7 @@ namespace NzbDrone.Core.Test database.Insert(tomorrow); database.Insert(twoDays); database.Insert(sevenDays); + database.Insert(series); //Act var result = mocker.Resolve().Tomorrow(); @@ -119,6 +137,8 @@ namespace NzbDrone.Core.Test //Assert Assert.AreEqual(1, result.Count); Assert.AreEqual(tomorrow.Title, result[0].Title); + result[0].Series.Should().NotBeNull(); + result[0].Series.SeriesId.Should().NotBe(0); } [Test] @@ -134,12 +154,17 @@ namespace NzbDrone.Core.Test database.Insert(tomorrow); database.Insert(twoDays); database.Insert(sevenDays); + database.Insert(series); //Act var result = mocker.Resolve().Week(); //Assert Assert.AreEqual(2, result.Count); + result[0].Series.Should().NotBeNull(); + result[0].Series.SeriesId.Should().NotBe(0); + result[1].Series.Should().NotBeNull(); + result[1].Series.SeriesId.Should().NotBe(0); } } } From 431d850d32a36e8bed47c1c0d393ae921c6fe3be Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 20 Jun 2011 00:13:17 -0700 Subject: [PATCH 3/6] SeriesProvider gets QualityProfile in single call to DB. SeriesProvider.GetAllSeriesWithEpisodeCount gets seasonCount(with or without specials), total episode count & episodeWithFile count (excluding ignored episodes). Added tests for SeriesWithEpisodeCount. --- NzbDrone.Core.Test/SeriesProviderTest.cs | 141 ++++++++++++++++++- NzbDrone.Core/Providers/SeriesProvider.cs | 46 ++++-- NzbDrone.Core/Repository/Series.cs | 16 ++- NzbDrone.Web/Controllers/SeriesController.cs | 49 +++---- NzbDrone.Web/Models/SeriesModel.cs | 2 + NzbDrone.Web/Views/Series/Index.cshtml | 34 +---- 6 files changed, 197 insertions(+), 91 deletions(-) diff --git a/NzbDrone.Core.Test/SeriesProviderTest.cs b/NzbDrone.Core.Test/SeriesProviderTest.cs index 9064eb8d5..0ce55b3ab 100644 --- a/NzbDrone.Core.Test/SeriesProviderTest.cs +++ b/NzbDrone.Core.Test/SeriesProviderTest.cs @@ -65,11 +65,13 @@ namespace NzbDrone.Core.Test mocker.GetMock() .Setup(c => c.UseSeasonFolder).Returns(useSeasonFolder); - mocker.SetConstant(MockLib.GetEmptyDatabase()); - - + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + var fakeProfiles = Builder.CreateListOfSize(2).Build(); + db.InsertMany(fakeProfiles); + const string path = "C:\\Test\\"; const int tvDbId = 1234; const int qualityProfileId = 2; @@ -78,8 +80,6 @@ namespace NzbDrone.Core.Test var seriesProvider = mocker.Resolve(); seriesProvider.AddSeries(path, tvDbId, qualityProfileId); - - //Assert var series = seriesProvider.GetAllSeries(); series.Should().HaveCount(1); @@ -104,7 +104,6 @@ namespace NzbDrone.Core.Test Assert.IsNull(series); } - [Test] [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Sequence contains no elements")] public void Get_series_invalid_series_id_should_return_null() @@ -233,6 +232,7 @@ namespace NzbDrone.Core.Test .With(c => c.SeriesId = 11) .Build()); + db.InsertMany(Builder.CreateListOfSize(3).Build()); //Act, Assert var provider = mocker.Resolve(); @@ -240,5 +240,134 @@ namespace NzbDrone.Core.Test Assert.IsFalse(provider.IsMonitored(11)); Assert.IsFalse(provider.IsMonitored(1)); } + + [Test] + public void Get_Series_With_Count() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeQuality = Builder.CreateNew().Build(); + var fakeSeries = Builder.CreateNew().With(e => e.QualityProfileId = fakeQuality.QualityProfileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(10).WhereAll().Have(e => e.SeriesId = fakeSeries.SeriesId).Have(e => e.Ignored = false).WhereRandom(5).Have(e => e.EpisodeFileId = 0).Build(); + + db.Insert(fakeSeries); + db.Insert(fakeQuality); + db.InsertMany(fakeEpisodes); + + //Act + mocker.Resolve(); + var series = mocker.Resolve().GetAllSeriesWithEpisodeCount(true); + + //Assert + series.Should().HaveCount(1); + Assert.AreEqual(10, series[0].EpisodeCount); + Assert.AreEqual(5, series[0].EpisodeFileCount); + } + + [Test] + public void Get_Series_With_Count_AllIgnored() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeQuality = Builder.CreateNew().Build(); + var fakeSeries = Builder.CreateNew().With(e => e.QualityProfileId = fakeQuality.QualityProfileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(10).WhereAll().Have(e => e.SeriesId = fakeSeries.SeriesId).Have(e => e.Ignored = true).WhereRandom(5).Have(e => e.EpisodeFileId = 0).Build(); + + db.Insert(fakeSeries); + db.Insert(fakeQuality); + db.InsertMany(fakeEpisodes); + + //Act + mocker.Resolve(); + var series = mocker.Resolve().GetAllSeriesWithEpisodeCount(true); + + //Assert + series.Should().HaveCount(1); + Assert.AreEqual(0, series[0].EpisodeCount); + Assert.AreEqual(0, series[0].EpisodeFileCount); + } + + [Test] + public void Get_Series_With_Count_AllDownloaded() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeQuality = Builder.CreateNew().Build(); + var fakeSeries = Builder.CreateNew().With(e => e.QualityProfileId = fakeQuality.QualityProfileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(10).WhereAll().Have(e => e.SeriesId = fakeSeries.SeriesId).Have(e => e.Ignored = false).Build(); + + db.Insert(fakeSeries); + db.Insert(fakeQuality); + db.InsertMany(fakeEpisodes); + + //Act + mocker.Resolve(); + var series = mocker.Resolve().GetAllSeriesWithEpisodeCount(true); + + //Assert + series.Should().HaveCount(1); + Assert.AreEqual(10, series[0].EpisodeCount); + Assert.AreEqual(10, series[0].EpisodeFileCount); + } + + [Test] + public void Get_Series_With_Count_Half_Ignored() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeQuality = Builder.CreateNew().Build(); + var fakeSeries = Builder.CreateNew().With(e => e.QualityProfileId = fakeQuality.QualityProfileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(10) + .WhereAll().Have(e => e.SeriesId = fakeSeries.SeriesId) + .WhereTheFirst(5).Have(e => e.Ignored = false) + .WhereTheLast(5).Have(e => e.Ignored = true) + .Build(); + + db.Insert(fakeSeries); + db.Insert(fakeQuality); + db.InsertMany(fakeEpisodes); + + //Act + mocker.Resolve(); + var series = mocker.Resolve().GetAllSeriesWithEpisodeCount(true); + + //Assert + series.Should().HaveCount(1); + Assert.AreEqual(5, series[0].EpisodeCount); + Assert.AreEqual(5, series[0].EpisodeFileCount); + } + + [Test] + public void Get_Single_Series() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeQuality = Builder.CreateNew().Build(); + var fakeSeries = Builder.CreateNew() + .With(e => e.QualityProfileId = fakeQuality.QualityProfileId) + .With(e => e.SeriesId = 1) + .Build(); + + db.Insert(fakeSeries); + db.Insert(fakeQuality); + + //Act + mocker.Resolve(); + var series = mocker.Resolve().GetSeries(1); + + //Assert + series.QualityProfile.Should().NotBeNull(); + series.QualityProfileId.Should().Be(fakeQuality.QualityProfileId); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/SeriesProvider.cs b/NzbDrone.Core/Providers/SeriesProvider.cs index 127e9f08a..611e1e6c4 100644 --- a/NzbDrone.Core/Providers/SeriesProvider.cs +++ b/NzbDrone.Core/Providers/SeriesProvider.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using NLog; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Repository; +using NzbDrone.Core.Repository.Quality; using PetaPoco; using TvdbLib.Data; @@ -17,17 +18,15 @@ namespace NzbDrone.Core.Providers private readonly ConfigProvider _configProvider; private readonly TvDbProvider _tvDbProvider; private readonly IDatabase _database; - private readonly QualityProvider _qualityProvider; private readonly SceneMappingProvider _sceneNameMappingProvider; private static readonly Regex TimeRegex = new Regex(@"^(?