From 0972c956b8763bd45eb6f3cd8bdb1088a4073425 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 19 Jun 2011 16:44:45 -0700 Subject: [PATCH 1/4] HistoryProvider will return History Items with Episode and SeriesTitle. --- NzbDrone.Core/Providers/HistoryProvider.cs | 13 +++++-- NzbDrone.Core/Repository/History.cs | 6 ++++ NzbDrone.Web/Controllers/HistoryController.cs | 34 +++++++------------ 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/NzbDrone.Core/Providers/HistoryProvider.cs b/NzbDrone.Core/Providers/HistoryProvider.cs index e389ded79..98a1ab883 100644 --- a/NzbDrone.Core/Providers/HistoryProvider.cs +++ b/NzbDrone.Core/Providers/HistoryProvider.cs @@ -25,9 +25,18 @@ namespace NzbDrone.Core.Providers { } - public virtual IEnumerable AllItems() + public virtual List AllItems() { - return _database.Query(""); + return _database.Fetch(""); + } + + public virtual List AllItemsWithRelationships() + { + return _database.Fetch(@" + SELECT History.*, Series.Title as SeriesTitle, Episodes.* FROM History + INNER JOIN Series ON History.SeriesId = Series.SeriesId + INNER JOIN Episodes ON History.EpisodeId = Episodes.EpisodeId + "); } public virtual void Purge() diff --git a/NzbDrone.Core/Repository/History.cs b/NzbDrone.Core/Repository/History.cs index a062d1c37..d34d6c2b2 100644 --- a/NzbDrone.Core/Repository/History.cs +++ b/NzbDrone.Core/Repository/History.cs @@ -16,5 +16,11 @@ namespace NzbDrone.Core.Repository public DateTime Date { get; set; } public bool IsProper { get; set; } public string Indexer { get; set; } + + [ResultColumn] + public Episode Episode { get; set; } + + [ResultColumn] + public string SeriesTitle { get; set; } } } \ No newline at end of file diff --git a/NzbDrone.Web/Controllers/HistoryController.cs b/NzbDrone.Web/Controllers/HistoryController.cs index 344af644a..1802396f8 100644 --- a/NzbDrone.Web/Controllers/HistoryController.cs +++ b/NzbDrone.Web/Controllers/HistoryController.cs @@ -46,30 +46,20 @@ namespace NzbDrone.Web.Controllers [GridAction] public ActionResult _AjaxBinding() { - var historyDb = _historyProvider.AllItems(); - - var history = new List(); - - foreach (var item in historyDb) - { - var episode = _episodeProvider.GetEpisode(item.EpisodeId); - var series = _seriesProvider.GetSeries(item.SeriesId); - - history.Add(new HistoryModel + var history = _historyProvider.AllItemsWithRelationships().Select(h => new HistoryModel { - HistoryId = item.HistoryId, - SeasonNumber = episode.SeasonNumber, - EpisodeNumber = episode.EpisodeNumber, - EpisodeTitle = episode.Title, - EpisodeOverview = episode.Overview, - SeriesTitle = series.Title, - NzbTitle = item.NzbTitle, - Quality = item.Quality.ToString(), - IsProper = item.IsProper, - Date = item.Date, - Indexer = item.Indexer + HistoryId = h.HistoryId, + SeasonNumber = h.Episode.SeasonNumber, + EpisodeNumber = h.Episode.EpisodeNumber, + EpisodeTitle = h.Episode.Title, + EpisodeOverview = h.Episode.Overview, + SeriesTitle = h.SeriesTitle, + NzbTitle = h.NzbTitle, + Quality = h.Quality.ToString(), + IsProper = h.IsProper, + Date = h.Date, + Indexer = h.Indexer }); - } return View(new GridModel(history)); } From 63a2664d8a2016fe76a342ea0848bb6bda7fd3c8 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 19 Jun 2011 17:02:10 -0700 Subject: [PATCH 2/4] Test for HistoryProvider.AllItemsWithRelationships --- NzbDrone.Core.Test/HistoryProviderTest.cs | 36 +++++++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/NzbDrone.Core.Test/HistoryProviderTest.cs b/NzbDrone.Core.Test/HistoryProviderTest.cs index b7c405de4..f127b89e3 100644 --- a/NzbDrone.Core.Test/HistoryProviderTest.cs +++ b/NzbDrone.Core.Test/HistoryProviderTest.cs @@ -29,7 +29,6 @@ namespace NzbDrone.Core.Test db.InsertMany(historyItem); - //Act var result = mocker.Resolve().AllItems(); @@ -37,6 +36,39 @@ namespace NzbDrone.Core.Test result.Should().HaveSameCount(historyItem); } + [Test] + public void AllItemsWithRelationships() + { + //Setup + var seriesOne = Builder.CreateNew().With(s => s.SeriesId = 12345).Build(); + var seriesTwo = Builder.CreateNew().With(s => s.SeriesId = 54321).Build(); + + var episodes = Builder.CreateListOfSize(10).Build(); + + var historyItems = Builder.CreateListOfSize(10).WhereTheFirst(5).Have(h => h.SeriesId = seriesOne.SeriesId).WhereTheLast(5).Have(h => h.SeriesId = seriesTwo.SeriesId).Build(); + + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + db.InsertMany(historyItems); + db.InsertMany(episodes); + db.Insert(seriesOne); + db.Insert(seriesTwo); + + //Act + var result = mocker.Resolve().AllItemsWithRelationships(); + + //Assert + result.Should().HaveSameCount(historyItems); + + foreach (var history in result) + { + Assert.NotNull(history.Episode); + Assert.That(!String.IsNullOrEmpty(history.SeriesTitle)); + } + } + [Test] public void PurgeItem() { @@ -157,7 +189,5 @@ namespace NzbDrone.Core.Test Assert.AreEqual(history.Quality, storedHistory.First().Quality); Assert.AreEqual(history.IsProper, storedHistory.First().IsProper); } - - } } \ No newline at end of file From cf324ace7317112ce0bcb2dff76f8887802b2269 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 19 Jun 2011 17:23:23 -0700 Subject: [PATCH 3/4] Episode EpisodeFile changed to ResultColumn instead of Ignore --- NzbDrone.Core/Repository/Episode.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/NzbDrone.Core/Repository/Episode.cs b/NzbDrone.Core/Repository/Episode.cs index 38afcc1d3..6e482e2ec 100644 --- a/NzbDrone.Core/Repository/Episode.cs +++ b/NzbDrone.Core/Repository/Episode.cs @@ -19,7 +19,6 @@ namespace NzbDrone.Core.Repository public string Title { get; set; } public DateTime AirDate { get; set; } - public string Overview { get; set; } public Boolean Ignored { get; set; } @@ -33,7 +32,6 @@ namespace NzbDrone.Core.Repository /// public DateTime? GrabDate { get; set; } - [Ignore] public EpisodeStatusType Status { @@ -58,15 +56,12 @@ namespace NzbDrone.Core.Repository } } - [Ignore] public Series Series { get; set; } - - [Ignore] + [ResultColumn] public EpisodeFile EpisodeFile { get; set; } - public override string ToString() { string seriesTitle = Series == null ? "[NULL]" : Series.Title; From b084a3bc46a3cf3fc2a5698e2cdf0d068fe44053 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 19 Jun 2011 18:46:32 -0700 Subject: [PATCH 4/4] EpisodeProvider GetEpisode(s) returns episodes with EpisodeFiles. --- NzbDrone.Core.Test/EpisodeProviderTest.cs | 154 +++++++++++++++++++-- NzbDrone.Core/Providers/EpisodeProvider.cs | 62 ++++++++- 2 files changed, 198 insertions(+), 18 deletions(-) diff --git a/NzbDrone.Core.Test/EpisodeProviderTest.cs b/NzbDrone.Core.Test/EpisodeProviderTest.cs index c931c8a93..892e8d373 100644 --- a/NzbDrone.Core.Test/EpisodeProviderTest.cs +++ b/NzbDrone.Core.Test/EpisodeProviderTest.cs @@ -41,10 +41,39 @@ namespace NzbDrone.Core.Test var episode = mocker.Resolve().GetEpisode(1); //Assert - episode.ShouldHave().AllPropertiesBut(e => e.Series).EqualTo(fakeEpisodes.First()); + episode.ShouldHave().AllPropertiesBut(e => e.Series, e => e.EpisodeFile).EqualTo(fakeEpisodes.First()); episode.Series.ShouldHave().AllProperties().EqualTo(fakeSeries); } + [Test] + public void GetEpisode_with_EpisodeFile() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeSeries = Builder.CreateNew().Build(); + var fakeFile = Builder.CreateNew().With(f => f.EpisodeFileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(5) + .WhereAll().Have(e => e.SeriesId = 1).WhereTheFirst(1).Have(e => e.EpisodeFileId = 1).Have(e => e.EpisodeFile = fakeFile).Build(); + + + db.InsertMany(fakeEpisodes); + db.Insert(fakeFile); + + mocker.GetMock() + .Setup(p => p.GetSeries(1)) + .Returns(fakeSeries); + + //Act + var episode = mocker.Resolve().GetEpisode(1); + + //Assert + episode.ShouldHave().AllPropertiesBut(e => e.Series, e => e.EpisodeFile).EqualTo(fakeEpisodes.First()); + episode.Series.ShouldHave().AllProperties().EqualTo(fakeSeries); + episode.EpisodeFile.Should().NotBeNull(); + } + [Test] [ExpectedException(typeof(InvalidOperationException), ExpectedMessage = "Sequence contains no elements")] public void GetEpisodes_invalid_series() @@ -79,7 +108,6 @@ namespace NzbDrone.Core.Test result.Should().HaveCount(0); } - [Test] public void AttachSeries_list_success() { @@ -136,7 +164,6 @@ namespace NzbDrone.Core.Test var returnedEpisode = mocker.Resolve().AttachSeries(fakeEpisodes); } - [Test] public void GetEpisodesBySeason_success() { @@ -196,7 +223,6 @@ namespace NzbDrone.Core.Test mocker.VerifyAllMocks(); } - [Test] public void new_episodes_only_calls_Insert() { @@ -217,7 +243,7 @@ namespace NzbDrone.Core.Test .Returns(tvdbSeries); mocker.GetMock() - .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) + .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) .Returns(currentEpisodes); @@ -231,7 +257,6 @@ namespace NzbDrone.Core.Test mocker.VerifyAllMocks(); } - [Test] public void existing_episodes_only_calls_Update() { @@ -255,7 +280,7 @@ namespace NzbDrone.Core.Test .Returns(tvdbSeries); mocker.GetMock() - .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) + .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) .Returns(currentEpisodes); //Act @@ -267,7 +292,6 @@ namespace NzbDrone.Core.Test mocker.VerifyAllMocks(); } - [Test] public void should_try_to_get_existing_episode_using_tvdbid_first() { @@ -286,7 +310,7 @@ namespace NzbDrone.Core.Test var mocker = new AutoMoqer(); mocker.GetMock() - .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) + .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) .Returns(fakeEpisodeList); mocker.GetMock() @@ -334,7 +358,7 @@ namespace NzbDrone.Core.Test .Returns(tvdbSeries); mocker.GetMock() - .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) + .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) .Returns(new List { localEpisode }); //Act @@ -345,7 +369,6 @@ namespace NzbDrone.Core.Test mocker.GetMock().Verify(c => c.Update(localEpisode), Times.Once()); } - [Test] public void existing_episodes_keep_their_episodeId_file_id() { @@ -371,7 +394,7 @@ namespace NzbDrone.Core.Test var updatedEpisodes = new List(); mocker.GetMock() - .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) + .Setup(d => d.Fetch(It.IsAny(), It.IsAny())) .Returns(currentEpisodes); mocker.GetMock() @@ -389,7 +412,6 @@ namespace NzbDrone.Core.Test updatedEpisodes.Should().OnlyContain(c => c.Ignored == true); } - [Test] public void IsSeasonIgnored_should_return_true_if_all_episodes_ignored() { @@ -497,6 +519,112 @@ namespace NzbDrone.Core.Test episodes.Should().NotBeEmpty(); } + [Test] + public void GetEpisode_by_Season_Episode_with_EpisodeFile() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeSeries = Builder.CreateNew().Build(); + var fakeFile = Builder.CreateNew().With(f => f.EpisodeFileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(5) + .WhereAll().Have(e => e.SeriesId = 1).WhereTheFirst(1).Have(e => e.EpisodeFileId = 1).Have(e => e.EpisodeFile = fakeFile).Build(); + + db.InsertMany(fakeEpisodes); + db.Insert(fakeFile); + + mocker.GetMock() + .Setup(p => p.GetSeries(1)) + .Returns(fakeSeries); + + //Act + var episode = mocker.Resolve().GetEpisode(1, 1, 1); + + //Assert + episode.ShouldHave().AllPropertiesBut(e => e.Series, e => e.EpisodeFile).EqualTo(fakeEpisodes.First()); + episode.Series.ShouldHave().AllProperties().EqualTo(fakeSeries); + episode.EpisodeFile.Should().NotBeNull(); + } + + [Test] + public void GetEpisode_by_Season_Episode_without_EpisodeFile() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeSeries = Builder.CreateNew().Build(); + var fakeEpisodes = Builder.CreateListOfSize(5) + .WhereAll().Have(e => e.SeriesId = 1).WhereTheFirst(1).Have(e => e.EpisodeFileId = 0).Build(); + + db.InsertMany(fakeEpisodes); + + mocker.GetMock() + .Setup(p => p.GetSeries(1)) + .Returns(fakeSeries); + + //Act + var episode = mocker.Resolve().GetEpisode(1, 1, 1); + + //Assert + episode.ShouldHave().AllPropertiesBut(e => e.Series).EqualTo(fakeEpisodes.First()); + episode.Series.ShouldHave().AllProperties().EqualTo(fakeSeries); + episode.EpisodeFile.Should().BeNull(); + } + + [Test] + public void GetEpisode_by_AirDate_with_EpisodeFile() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeSeries = Builder.CreateNew().Build(); + var fakeFile = Builder.CreateNew().With(f => f.EpisodeFileId).Build(); + var fakeEpisodes = Builder.CreateListOfSize(5) + .WhereAll().Have(e => e.SeriesId = 1).WhereTheFirst(1).Have(e => e.EpisodeFileId = 1).Have(e => e.EpisodeFile = fakeFile).Build(); + + db.InsertMany(fakeEpisodes); + db.Insert(fakeFile); + mocker.GetMock() + .Setup(p => p.GetSeries(1)) + .Returns(fakeSeries); + + //Act + var episode = mocker.Resolve().GetEpisode(1, fakeEpisodes[0].AirDate); + + //Assert + episode.ShouldHave().AllPropertiesBut(e => e.Series, e => e.EpisodeFile).EqualTo(fakeEpisodes.First()); + episode.Series.ShouldHave().AllProperties().EqualTo(fakeSeries); + episode.EpisodeFile.Should().NotBeNull(); + } + + [Test] + public void GetEpisode_by_AirDate_without_EpisodeFile() + { + var mocker = new AutoMoqer(); + var db = MockLib.GetEmptyDatabase(); + mocker.SetConstant(db); + + var fakeSeries = Builder.CreateNew().Build(); + var fakeEpisodes = Builder.CreateListOfSize(5) + .WhereAll().Have(e => e.SeriesId = 1).WhereTheFirst(1).Have(e => e.EpisodeFileId = 0).Build(); + + db.InsertMany(fakeEpisodes); + + mocker.GetMock() + .Setup(p => p.GetSeries(1)) + .Returns(fakeSeries); + + //Act + var episode = mocker.Resolve().GetEpisode(1, fakeEpisodes[0].AirDate); + + //Assert + episode.ShouldHave().AllPropertiesBut(e => e.Series).EqualTo(fakeEpisodes.First()); + episode.Series.ShouldHave().AllProperties().EqualTo(fakeSeries); + episode.EpisodeFile.Should().BeNull(); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/EpisodeProvider.cs b/NzbDrone.Core/Providers/EpisodeProvider.cs index 10825b9a2..13ca76b1d 100644 --- a/NzbDrone.Core/Providers/EpisodeProvider.cs +++ b/NzbDrone.Core/Providers/EpisodeProvider.cs @@ -35,27 +35,73 @@ namespace NzbDrone.Core.Providers public virtual Episode GetEpisode(long id) { - return AttachSeries(_database.Single(id)); + var episode = AttachSeries(_database.Fetch(@"SELECT * FROM Episodes + LEFT JOIN EpisodeFiles ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId + WHERE EpisodeId = @0", id).Single()); + if (episode.EpisodeFileId == 0) + episode.EpisodeFile = null; + + return episode; } public virtual Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber) { - return AttachSeries(_database.SingleOrDefault("WHERE SeriesId = @0 AND SeasonNumber = @1 AND EpisodeNumber = @2", seriesId, seasonNumber, episodeNumber)); + var episode = AttachSeries(_database.Fetch(@"SELECT * FROM Episodes + LEFT JOIN EpisodeFiles ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId + WHERE Episodes.SeriesId = @0 AND Episodes.SeasonNumber = @1 AND Episodes.EpisodeNumber = @2", seriesId, seasonNumber, episodeNumber).SingleOrDefault()); + + if (episode == null) + return null; + + if (episode.EpisodeFileId == 0) + episode.EpisodeFile = null; + + return episode; } public virtual Episode GetEpisode(int seriesId, DateTime date) { - return AttachSeries(_database.SingleOrDefault("WHERE SeriesId = @0 AND AirDate = @1", seriesId, date.Date)); + var episode = AttachSeries(_database.Fetch(@"SELECT * FROM Episodes + LEFT JOIN EpisodeFiles ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId + WHERE Episodes.SeriesId = @0 AND AirDate = @1", seriesId, date.Date)).SingleOrDefault(); + + if (episode == null) + return null; + + if (episode.EpisodeFileId == 0) + episode.EpisodeFile = null; + + return episode; } public virtual IList GetEpisodeBySeries(long seriesId) { - return AttachSeries(_database.Fetch("WHERE SeriesId = @0", seriesId)); + var episodes = AttachSeries(_database.Fetch(@"SELECT * FROM Episodes + LEFT JOIN EpisodeFiles ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId + WHERE Episodes.SeriesId = @0", seriesId)); + + foreach (var episode in episodes) + { + if (episode.EpisodeFileId == 0) + episode.EpisodeFile = null; + } + + return episodes; } public virtual IList GetEpisodesBySeason(long seriesId, int seasonNumber) { - return AttachSeries(_database.Fetch("WHERE SeriesId = @0 AND SeasonNumber = @1", seriesId, seasonNumber)); + var episodes = AttachSeries(_database.Fetch(@"SELECT * FROM Episodes + LEFT JOIN EpisodeFiles ON Episodes.EpisodeFileId = EpisodeFiles.EpisodeFileId + WHERE Episodes.SeriesId = @0 AND Episodes.SeasonNumber = @1", seriesId, seasonNumber)); + + foreach (var episode in episodes) + { + if (episode.EpisodeFileId == 0) + episode.EpisodeFile = null; + } + + return episodes; } public virtual List GetEpisodes(EpisodeParseResult parseResult) @@ -78,6 +124,12 @@ namespace NzbDrone.Core.Providers episodes.Add(episode); } + foreach (var episode in episodes) + { + if (episode.EpisodeFileId == 0) + episode.EpisodeFile = null; + } + return episodes; }