diff --git a/Kyoo.SqLite/SqLiteContext.cs b/Kyoo.SqLite/SqLiteContext.cs index ca1a651e..1a2a392a 100644 --- a/Kyoo.SqLite/SqLiteContext.cs +++ b/Kyoo.SqLite/SqLiteContext.cs @@ -119,7 +119,8 @@ namespace Kyoo.SqLite /// protected override bool IsDuplicateException(Exception ex) { - return ex.InnerException is SqliteException { SqliteExtendedErrorCode: 2067 /*SQLITE_CONSTRAINT_UNIQUE*/}; + return ex.InnerException is SqliteException { SqliteExtendedErrorCode: 2067 /*SQLITE_CONSTRAINT_UNIQUE*/} + or SqliteException { SqliteExtendedErrorCode: 1555 /*SQLITE_CONSTRAINT_PRIMARYKEY*/}; } /// diff --git a/Kyoo.Tests/Library/RepositoryActivator.cs b/Kyoo.Tests/Library/RepositoryActivator.cs index 0d2dda01..42468a49 100644 --- a/Kyoo.Tests/Library/RepositoryActivator.cs +++ b/Kyoo.Tests/Library/RepositoryActivator.cs @@ -24,9 +24,7 @@ namespace Kyoo.Tests StudioRepository studio = new(_database); PeopleRepository people = new(_database, provider, new Lazy(() => LibraryManager.ShowRepository)); - ShowRepository show = new(_database, studio, people, genre, provider, - new Lazy(() => LibraryManager.SeasonRepository), - new Lazy(() => LibraryManager.EpisodeRepository)); + ShowRepository show = new(_database, studio, people, genre, provider); SeasonRepository season = new(_database, provider, show, new Lazy(() => LibraryManager.EpisodeRepository)); LibraryItemRepository libraryItem = new(_database, diff --git a/Kyoo.Tests/Library/RepositoryTests.cs b/Kyoo.Tests/Library/RepositoryTests.cs index 16bc4fa9..e8504a16 100644 --- a/Kyoo.Tests/Library/RepositoryTests.cs +++ b/Kyoo.Tests/Library/RepositoryTests.cs @@ -74,5 +74,17 @@ namespace Kyoo.Tests await _repository.Delete(TestSample.Get()); Assert.Equal(0, await _repository.GetCount()); } + + [Fact] + public async Task CreateTest() + { + await Assert.ThrowsAsync(() => _repository.Create(TestSample.Get())); + await _repository.Delete(TestSample.Get()); + + T expected = TestSample.Get(); + expected.ID = 0; + await _repository.Create(expected); + KAssert.DeepEqual(expected, await _repository.Get(expected.Slug)); + } } } \ No newline at end of file diff --git a/Kyoo.Tests/Library/SpecificTests/GlobalTests.cs b/Kyoo.Tests/Library/SpecificTests/GlobalTests.cs index 284c2ad7..57b8c4c3 100644 --- a/Kyoo.Tests/Library/SpecificTests/GlobalTests.cs +++ b/Kyoo.Tests/Library/SpecificTests/GlobalTests.cs @@ -1,3 +1,5 @@ +using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; using Kyoo.Models; @@ -5,12 +7,25 @@ using Xunit; namespace Kyoo.Tests.SpecificTests { - public class GlobalTests + public class GlobalTests : IDisposable, IAsyncDisposable { + private readonly RepositoryActivator _repositories; + + public GlobalTests() + { + _repositories = new RepositoryActivator(); + } + + [Fact] + [SuppressMessage("ReSharper", "EqualExpressionComparison")] + public void SampleTest() + { + Assert.False(ReferenceEquals(TestSample.Get(), TestSample.Get())); + } + [Fact] public async Task DeleteShowWithEpisodeAndSeason() { - RepositoryActivator repositories = new(); Show show = TestSample.Get(); show.Seasons = new[] { @@ -20,13 +35,24 @@ namespace Kyoo.Tests.SpecificTests { TestSample.Get() }; - await repositories.Context.AddAsync(show); + await _repositories.Context.AddAsync(show); - Assert.Equal(1, await repositories.LibraryManager.ShowRepository.GetCount()); - await repositories.LibraryManager.ShowRepository.Delete(show); - Assert.Equal(0, await repositories.LibraryManager.ShowRepository.GetCount()); - Assert.Equal(0, await repositories.LibraryManager.SeasonRepository.GetCount()); - Assert.Equal(0, await repositories.LibraryManager.EpisodeRepository.GetCount()); + Assert.Equal(1, await _repositories.LibraryManager.ShowRepository.GetCount()); + await _repositories.LibraryManager.ShowRepository.Delete(show); + Assert.Equal(0, await _repositories.LibraryManager.ShowRepository.GetCount()); + Assert.Equal(0, await _repositories.LibraryManager.SeasonRepository.GetCount()); + Assert.Equal(0, await _repositories.LibraryManager.EpisodeRepository.GetCount()); + } + + public void Dispose() + { + _repositories.Dispose(); + GC.SuppressFinalize(this); + } + + public ValueTask DisposeAsync() + { + return _repositories.DisposeAsync(); } } } \ No newline at end of file diff --git a/Kyoo.Tests/Library/SpecificTests/ShowTests.cs b/Kyoo.Tests/Library/SpecificTests/ShowTests.cs index 5cfcfea2..c49ca824 100644 --- a/Kyoo.Tests/Library/SpecificTests/ShowTests.cs +++ b/Kyoo.Tests/Library/SpecificTests/ShowTests.cs @@ -178,5 +178,43 @@ namespace Kyoo.Tests.SpecificTests Assert.Null(edited.Genres); Assert.Null(edited.Studio); } + + [Fact] + public async Task CreateWithRelationsTest() + { + Show expected = TestSample.Get(); + expected.ID = 0; + expected.Slug = "created-relation-test"; + expected.ExternalIDs = new[] + { + new MetadataID + { + First = expected, + Second = new Provider("provider", "provider.png"), + DataID = "ID" + } + }; + expected.Genres = new[] + { + new Genre + { + Name = "Genre", + Slug = "genre" + } + }; + expected.People = new[] + { + new PeopleRole + { + People = TestSample.Get(), + Show = expected, + ForPeople = false, + Role = "actor" + } + }; + expected.Studio = new Studio("studio"); + Show created = await _repository.Create(expected); + KAssert.DeepEqual(expected, created); + } } } \ No newline at end of file diff --git a/Kyoo.Tests/Library/TestContext.cs b/Kyoo.Tests/Library/TestContext.cs index a3d2a51e..30f8beb5 100644 --- a/Kyoo.Tests/Library/TestContext.cs +++ b/Kyoo.Tests/Library/TestContext.cs @@ -93,6 +93,7 @@ namespace Kyoo.Tests public void Dispose() { _connection.Close(); + GC.SuppressFinalize(this); } public async ValueTask DisposeAsync() diff --git a/Kyoo.Tests/Library/TestSample.cs b/Kyoo.Tests/Library/TestSample.cs index 3ad39969..7abf1ed1 100644 --- a/Kyoo.Tests/Library/TestSample.cs +++ b/Kyoo.Tests/Library/TestSample.cs @@ -6,11 +6,11 @@ namespace Kyoo.Tests { public static class TestSample { - private static readonly Dictionary Samples = new() + private static readonly Dictionary> Samples = new() { { typeof(Show), - new Show + () => new Show { ID = 1, Slug = "anohana", @@ -37,7 +37,7 @@ namespace Kyoo.Tests }, { typeof(Season), - new Season + () => new Season { ID = 1, ShowSlug = "anohana", @@ -52,7 +52,7 @@ namespace Kyoo.Tests }, { typeof(Episode), - new Episode + () => new Episode { ID = 1, ShowSlug = "anohana", @@ -70,7 +70,7 @@ namespace Kyoo.Tests }, { typeof(People), - new People + () => new People { ID = 1, Slug = "the-actor", @@ -82,7 +82,7 @@ namespace Kyoo.Tests public static T Get() { - return (T)Samples[typeof(T)]; + return (T)Samples[typeof(T)](); } } } \ No newline at end of file diff --git a/Kyoo/Controllers/Repositories/ShowRepository.cs b/Kyoo/Controllers/Repositories/ShowRepository.cs index deeea623..360d5d28 100644 --- a/Kyoo/Controllers/Repositories/ShowRepository.cs +++ b/Kyoo/Controllers/Repositories/ShowRepository.cs @@ -33,14 +33,6 @@ namespace Kyoo.Controllers /// A provider repository to handle externalID creation and deletion /// private readonly IProviderRepository _providers; - /// - /// A lazy loaded season repository to handle cascade deletion (seasons deletion whith it's show) - /// - private readonly Lazy _seasons; - /// - /// A lazy loaded episode repository to handle cascade deletion (episode deletion whith it's show) - /// - private readonly Lazy _episodes; /// protected override Expression> DefaultSort => x => x.Title; @@ -53,15 +45,11 @@ namespace Kyoo.Controllers /// A people repository /// A genres repository /// A provider repository - /// A lazy loaded season repository - /// A lazy loaded episode repository public ShowRepository(DatabaseContext database, IStudioRepository studios, IPeopleRepository people, IGenreRepository genres, - IProviderRepository providers, - Lazy seasons, - Lazy episodes) + IProviderRepository providers) : base(database) { _database = database; @@ -69,8 +57,6 @@ namespace Kyoo.Controllers _people = people; _genres = genres; _providers = providers; - _seasons = seasons; - _episodes = episodes; } @@ -103,12 +89,16 @@ namespace Kyoo.Controllers await base.Validate(resource); if (resource.Studio != null) resource.Studio = await _studios.CreateIfNotExists(resource.Studio); - resource.Genres = await TaskUtils.DefaultIfNull(resource.Genres - ?.SelectAsync(x => _genres.CreateIfNotExists(x)) - .ToListAsync()); + resource.GenreLinks = resource.Genres? - .Select(x => Link.UCreate(resource, x)) + .Select(x => Link.Create(resource, x)) .ToList(); + await resource.GenreLinks.ForEachAsync(async id => + { + id.Second = await _genres.CreateIfNotExists(id.Second); + id.SecondID = id.Second.ID; + _database.Entry(id.Second).State = EntityState.Detached; + }); await resource.ExternalIDs.ForEachAsync(async id => { id.Second = await _providers.CreateIfNotExists(id.Second); @@ -139,8 +129,8 @@ namespace Kyoo.Controllers if (changed.Genres != null || resetOld) { - await Database.Entry(resource).Collection(x => x.GenreLinks).LoadAsync(); - resource.GenreLinks = changed.Genres?.Select(x => Link.UCreate(resource, x)).ToList(); + await Database.Entry(resource).Collection(x => x.Genres).LoadAsync(); + resource.Genres = changed.Genres; } if (changed.People != null || resetOld) @@ -191,18 +181,8 @@ namespace Kyoo.Controllers /// public override async Task Delete(Show obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - _database.Entry(obj).State = EntityState.Deleted; await _database.SaveChangesAsync(); - - // TODO handle that with events maybe. (for now, seasons & episodes might not be loaded) - if (obj.Seasons != null) - await _seasons.Value.DeleteRange(obj.Seasons); - - if (obj.Episodes != null) - await _episodes.Value.DeleteRange(obj.Episodes); } } } \ No newline at end of file