diff --git a/Kyoo.Common/Controllers/ILibraryManager.cs b/Kyoo.Common/Controllers/ILibraryManager.cs index 8268cb66..ff239fb1 100644 --- a/Kyoo.Common/Controllers/ILibraryManager.cs +++ b/Kyoo.Common/Controllers/ILibraryManager.cs @@ -1,9 +1,10 @@ -using Kyoo.Models; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; +using Kyoo.Models; namespace Kyoo.Controllers { + // ReSharper disable once PossibleInterfaceMemberAmbiguity public interface ILibraryManager { // Get by slug @@ -16,21 +17,22 @@ namespace Kyoo.Controllers Genre GetGenre(string slug); Studio GetStudio(string slug); People GetPeople(string slug); - ProviderID GetProvider(string name); // Get all IEnumerable GetLibraries(); IEnumerable GetCollections(); IEnumerable GetShows(); + IEnumerable GetSeasons(); IEnumerable GetEpisodes(); - IEnumerable GetTracks(); IEnumerable GetStudios(); IEnumerable GetPeoples(); IEnumerable GetGenres(); // Search + IEnumerable SearchLibraries(string searchQuery); IEnumerable SearchCollections(string searchQuery); IEnumerable SearchShows(string searchQuery); + IEnumerable SearchSeasons(string searchQuery); IEnumerable SearchEpisodes(string searchQuery); IEnumerable SearchGenres(string searchQuery); IEnumerable SearchStudios(string searchQuery); @@ -42,17 +44,34 @@ namespace Kyoo.Controllers IEnumerable GetEpisodes(string showSlug, long seasonNumber); //Register values - void Register(object obj); - Task Edit(object obj, bool resetOld); - void RegisterShowLinks(Library library, Collection collection, Show show); - Task SaveChanges(); + void RegisterLibrary(Library library); + void RegisterCollection(Collection collection); + void RegisterShow(Show show); + void RegisterSeason(Season season); + void RegisterEpisode(Episode episode); + void RegisterGenre(Genre genre); + void RegisterStudio(Studio studio); + void RegisterPeople(People people); - // Validate values - IEnumerable Validate(IEnumerable id); + // Edit values + void EditLibrary(Library library, bool resetOld); + void EditCollection(Collection collection, bool resetOld); + void EditShow(Show show, bool resetOld); + void EditSeason(Season season, bool resetOld); + void EditEpisode(Episode episode, bool resetOld); + void EditGenre(Genre genre, bool resetOld); + void EditStudio(Studio studio, bool resetOld); + void EditPeople(People people, bool resetOld); + - // Remove values - void RemoveShow(Show show); - void RemoveSeason(Season season); - void RemoveEpisode(Episode episode); + // Delete values + void DelteLibrary(Library library); + void DeleteCollection(Collection collection); + void DeleteShow(Show show); + void DeleteSeason(Season season); + void DeleteEpisode(Episode episode); + void DeleteGenre(Genre genre); + void DeleteStudio(Studio studio); + void DeletePeople(People people); } } diff --git a/Kyoo.Common/Controllers/IRepository.cs b/Kyoo.Common/Controllers/IRepository.cs new file mode 100644 index 00000000..4ff868e6 --- /dev/null +++ b/Kyoo.Common/Controllers/IRepository.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Kyoo.Models; + +namespace Kyoo.Controllers +{ + public interface IRepository + { + T Get(string slug); + IEnumerable Search(string query); + IEnumerable GetAll(); + T Create(T obj); + T CreateIfNotExists(T obj); + void Edit(T edited, bool resetOld); + void Delete(string slug); + } + + public interface IShowRepository : IRepository {} + + public interface ISeasonRepository : IRepository + { + Season Get(string showSlug, int seasonNumber); + } + + public interface IEpisodeRepository : IRepository + { + Episode Get(string showSlug, int seasonNumber, int episodeNumber); + } + + public interface ILibraryRepository : IRepository {} + public interface ICollectionRepository : IRepository {} + public interface IGenreRepository : IRepository {} + public interface IStudioRepository : IRepository {} + public interface IPeopleRepository : IRepository {} +} \ No newline at end of file diff --git a/Kyoo/Controllers/LibraryManager.cs b/Kyoo/Controllers/LibraryManager.cs index 8d7aaaf2..393ada95 100644 --- a/Kyoo/Controllers/LibraryManager.cs +++ b/Kyoo/Controllers/LibraryManager.cs @@ -12,383 +12,46 @@ namespace Kyoo.Controllers { public class LibraryManager : ILibraryManager { - private const int MaxSaveRetry = 3; - private readonly DatabaseContext _database; + private readonly ILibraryRepository _library; - - public LibraryManager(DatabaseContext database) + public LibraryManager(ILibraryRepository library) { - _database = database; + _library = library; } - #region GetBySlug - public Library GetLibrary(string librarySlug) + public Library Get(string slug) { - return _database.Libraries.FirstOrDefault(library => library.Slug == librarySlug); - } - - public Collection GetCollection(string slug) - { - return _database.Collections.FirstOrDefault(col => col.Slug == slug); + throw new NotImplementedException(); } - public Show GetShow(string slug) + public IEnumerable Search(string query) { - return _database.Shows.FirstOrDefault(show => show.Slug == slug); + throw new NotImplementedException(); } - public Season GetSeason(string showSlug, long seasonNumber) + public IEnumerable GetAll() { - return _database.Seasons.FirstOrDefault(x => x.Show.Slug == showSlug && x.SeasonNumber == seasonNumber); + throw new NotImplementedException(); } - public Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber) + public Library Create(Library obj) { - return _database.Episodes.FirstOrDefault(x => x.EpisodeNumber == episodeNumber - && x.SeasonNumber == seasonNumber - && x.Show.Slug == showSlug); - } - - public Episode GetMovieEpisode(string movieSlug) - { - return _database.Episodes.FirstOrDefault(x => x.Show.Slug == movieSlug); + throw new NotImplementedException(); } - public Genre GetGenre(string slug) + public Library CreateIfNotExists(Library obj) { - return _database.Genres.FirstOrDefault(genre => genre.Slug == slug); + throw new NotImplementedException(); } - public Studio GetStudio(string slug) + public void Edit(Library edited, bool resetOld) { - return _database.Studios.FirstOrDefault(studio => studio.Slug == slug); + throw new NotImplementedException(); } - public People GetPeople(string slug) + public void Delete(string slug) { - return _database.Peoples.FirstOrDefault(people => people.Slug == slug); + throw new NotImplementedException(); } - - public ProviderID GetProvider(string name) - { - return _database.Providers.FirstOrDefault(x => x.Name == name); - } - - #endregion - - #region GetAll - public IEnumerable GetLibraries() - { - return _database.Libraries; - } - - public IEnumerable GetCollections() - { - return _database.Collections; - } - - public IEnumerable GetShows() - { - return _database.Shows; - } - - public IEnumerable GetEpisodes() - { - return _database.Episodes; - } - - public IEnumerable GetGenres() - { - return _database.Genres; - } - - public IEnumerable GetStudios() - { - return _database.Studios; - } - - public IEnumerable GetPeoples() - { - return _database.Peoples; - } - - public IEnumerable GetTracks() - { - return _database.Tracks; - } - - #endregion - - #region GetHelper - public IEnumerable GetLibrariesPath() - { - IEnumerable paths = new List(); - return Enumerable.Aggregate(_database.Libraries, paths, (current, lib) => current.Concat(lib.Paths)); - } - - public Show GetShowByPath(string path) - { - return _database.Shows.FirstOrDefault(show => show.Path == path); - } - - public IEnumerable GetEpisodes(string showSlug, long seasonNumber) - { - return _database.Episodes.Where(x => x.Show.Slug == showSlug && x.SeasonNumber == seasonNumber); - } - #endregion - - #region Search - public IEnumerable SearchCollections(string searchQuery) - { - return _database.Collections.Where(collection => EF.Functions.Like(collection.Name, $"%{searchQuery}%")) - .Take(20); - } - - public IEnumerable SearchShows(string searchQuery) - { - return _database.Shows.FromSqlInterpolated($@"SELECT * FROM Shows WHERE Shows.Title LIKE {$"%{searchQuery}%"} - OR Shows.Aliases LIKE {$"%{searchQuery}%"}").Take(20); - } - - public IEnumerable SearchEpisodes(string searchQuery) - { - return _database.Episodes.Where(x => EF.Functions.Like(x.Title, $"%{searchQuery}%")).Take(20); - } - - public IEnumerable SearchGenres(string searchQuery) - { - return _database.Genres.Where(genre => EF.Functions.Like(genre.Name, $"%{searchQuery}%")) - .Take(20); - } - - public IEnumerable SearchStudios(string searchQuery) - { - return _database.Studios.Where(studio => EF.Functions.Like(studio.Name, $"%{searchQuery}%")) - .Take(20); - } - - public IEnumerable SearchPeople(string searchQuery) - { - return _database.Peoples.Where(people => EF.Functions.Like(people.Name, $"%{searchQuery}%")) - .OrderBy(x => x.ImgPrimary == null) - .ThenBy(x => x.Name) - .Take(20); - } - #endregion - - #region Register - public void Register(object obj) - { - if (obj == null) - return; - ValidateRootEntry(_database.Entry(obj), entry => - { - if (entry.State != EntityState.Detached) - return false; - - entry.State = EntityState.Added; - return true; - }); - } - - public void RegisterShowLinks(Library library, Collection collection, Show show) - { - if (collection != null) - { - _database.LibraryLinks.AddIfNotExist(new LibraryLink {Library = library, Collection = collection}, - x => x.Library == library && x.Collection == collection && x.ShowID == null); - _database.CollectionLinks.AddIfNotExist(new CollectionLink { Collection = collection, Show = show}, - x => x.Collection == collection && x.Show == show); - } - else - _database.LibraryLinks.AddIfNotExist(new LibraryLink {Library = library, Show = show}, - x => x.Library == library && x.Collection == null && x.Show == show); - } - - public Task SaveChanges() - { - return SaveChanges(0); - } - - private async Task SaveChanges(int retryCount) - { - ValidateChanges(); - try - { - await _database.SaveChangesAsync(); - } - catch (DbUpdateException) - { - if (retryCount < MaxSaveRetry) - await SaveChanges(retryCount + 1); - else - throw; - } - } - - public async Task Edit(object obj, bool resetOld) - { - _database.ChangeTracker.LazyLoadingEnabled = false; - _database.ChangeTracker.AutoDetectChangesEnabled = false; - - try - { - object existing = FindExisting(obj); - - if (existing == null) - throw new ItemNotFound($"No existing object (of type {obj.GetType().Name}) found on the databse."); - - if (resetOld) - Utility.Nullify(existing); - Utility.Merge(existing, obj); - - ValidateRootEntry(_database.Entry(existing), entry => entry.State != EntityState.Added); - - _database.ChangeTracker.DetectChanges(); - await _database.SaveChangesAsync(); - } - finally - { - _database.ChangeTracker.LazyLoadingEnabled = true; - _database.ChangeTracker.AutoDetectChangesEnabled = true; - } - } - #endregion - - #region ValidateValue - private void ValidateChanges() - { - _database.ChangeTracker.AutoDetectChangesEnabled = false; - try - { - foreach (EntityEntry sourceEntry in _database.ChangeTracker.Entries()) - { - if (sourceEntry.State != EntityState.Added && sourceEntry.State != EntityState.Modified) - continue; - - foreach (NavigationEntry navigation in sourceEntry.Navigations) - ValidateNavigation(navigation); - } - } - finally - { - _database.ChangeTracker.AutoDetectChangesEnabled = true; - _database.ChangeTracker.DetectChanges(); - } - } - - private void ValidateRootEntry(EntityEntry entry, Func shouldRun) - { - if (!shouldRun.Invoke(entry)) - return; - foreach (NavigationEntry navigation in entry.Navigations) - { - ValidateNavigation(navigation); - if (navigation.CurrentValue == null) - continue; - if (navigation.Metadata.IsCollection()) - { - IEnumerable entities = (IEnumerable)navigation.CurrentValue; - foreach (object childEntry in entities) - ValidateRootEntry(_database.Entry(childEntry), shouldRun); - } - else - ValidateRootEntry(_database.Entry(navigation.CurrentValue), shouldRun); - } - } - - private void ValidateNavigation(NavigationEntry navigation) - { - object oldValue = navigation.CurrentValue; - if (oldValue == null) - return; - object newValue = Validate(oldValue); - if (ReferenceEquals(oldValue, newValue)) - return; - navigation.CurrentValue = newValue; - if (!navigation.Metadata.IsCollection()) - _database.Entry(oldValue).State = EntityState.Detached; - } - - private T Validate(T obj) where T : class - { - switch (obj) - { - case null: - return null; - case IEnumerable enumerable: - return (T)Utility.RunGenericMethod( - this, - "ValidateList", - Utility.GetEnumerableType(enumerable), new [] {obj}); - } - - EntityState state = _database.Entry(obj).State; - if (state != EntityState.Added && state != EntityState.Detached) - return obj; - - return (T)(FindExisting(obj) ?? obj); - } - - public IEnumerable ValidateList(IEnumerable list) where T : class - { - return list.Select(x => - { - T tmp = Validate(x); - if (tmp != x) - _database.Entry(x).State = EntityState.Detached; - return tmp ?? x; - })/*.GroupBy(GetSlug).Select(x => x.First()).Where(x => x != null)*/.ToList(); - } - - private object FindExisting(object obj) - { - return obj switch - { - Library library => GetLibrary(library.Slug), - Collection collection => GetCollection(collection.Slug), - Show show => GetShow(show.Slug), - Season season => GetSeason(season.Show.Slug, season.SeasonNumber), - Episode episode => GetEpisode(episode.Show.Slug, episode.SeasonNumber, episode.EpisodeNumber), - Studio studio => GetStudio(studio.Slug), - People people => GetPeople(people.Slug), - Genre genre => GetGenre(genre.Slug), - ProviderID provider => GetProvider(provider.Name), - _ => null - }; - } - - public IEnumerable Validate(IEnumerable ids) - { - return ids?.Select(x => - { - x.Provider = _database.Providers.FirstOrDefault(y => y.Name == x.Provider.Name) ?? x.Provider; - return x; - }).GroupBy(x => x.Provider.Name).Select(x => x.First()).ToList(); - } - #endregion - - #region Remove - public void RemoveShow(Show show) - { - if (_database.Entry(show).State == EntityState.Detached) - _database.Shows.Attach(show); - _database.Shows.Remove(show); - } - - public void RemoveSeason(Season season) - { - if (_database.Entry(season).State == EntityState.Detached) - _database.Seasons.Attach(season); - _database.Seasons.Remove(season); - } - - public void RemoveEpisode(Episode episode) - { - if (_database.Entry(episode).State == EntityState.Detached) - _database.Episodes.Attach(episode); - _database.Episodes.Remove(episode); - } - #endregion } } diff --git a/Kyoo/Controllers/Repositories/ShowRepository.cs b/Kyoo/Controllers/Repositories/ShowRepository.cs new file mode 100644 index 00000000..51aacad2 --- /dev/null +++ b/Kyoo/Controllers/Repositories/ShowRepository.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Kyoo.Models; +using Microsoft.EntityFrameworkCore; + +namespace Kyoo.Controllers +{ + public class ShowRepository : IShowRepository + { + private readonly DatabaseContext _database; + private readonly ILibraryManager _library; + + public ShowRepository(DatabaseContext database, ILibraryManager library) + { + _database = database; + _library = library; + } + + public Show Get(string slug) + { + return _database.Shows.FirstOrDefault(x => x.Slug == slug); + } + + public IEnumerable Search(string query) + { + return _database.Shows.FromSqlInterpolated($@"SELECT * FROM Shows WHERE Shows.Title LIKE {$"%{query}%"} + OR Shows.Aliases LIKE {$"%{query}%"}").Take(20); + } + + public IEnumerable GetAll() + { + return _database.Shows.ToList(); + } + + public Show Create(Show obj) + { + if (obj == null) + throw new ArgumentNullException(nameof(obj)); + + obj.Genres = obj.Genres.Select(_library.CreateIfNotExists).ToList(); + + + _database.Shows.Add(obj); + _database.SaveChanges(); + return obj; + } + + public Show CreateIfNotExists(Show obj) + { + if (obj == null) + throw new ArgumentNullException(nameof(obj)); + + return Get(obj.Slug) ?? Create(obj); + } + + public void Edit(Show edited, bool resetOld) + { + throw new System.NotImplementedException(); + } + + public void Delete(string slug) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file