From 81f555ca7e0d4964fc45e285b38b5129d4b3ff0f Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 19 Jul 2020 00:15:34 +0200 Subject: [PATCH] Finishing the repositories's rework --- Kyoo.Common/Models/Track.cs | 7 +- .../Repositories/CollectionRepository.cs | 2 +- .../Repositories/EpisodeRepository.cs | 4 +- .../Repositories/GenreRepository.cs | 6 +- .../Repositories/LibraryRepository.cs | 112 ++----------- .../Repositories/PeopleRepository.cs | 114 ++------------ .../Repositories/ProviderRepository.cs | 109 ++----------- .../Repositories/SeasonRepository.cs | 128 +++------------ .../Repositories/ShowRepository.cs | 149 +++--------------- .../Repositories/StudioRepository.cs | 111 ++----------- .../Repositories/TrackRepository.cs | 110 ++++--------- 11 files changed, 144 insertions(+), 708 deletions(-) diff --git a/Kyoo.Common/Models/Track.cs b/Kyoo.Common/Models/Track.cs index a0688c32..61209807 100644 --- a/Kyoo.Common/Models/Track.cs +++ b/Kyoo.Common/Models/Track.cs @@ -93,9 +93,10 @@ namespace Kyoo.Models { if (Type != StreamType.Subtitle) return null; - string slug = $"/subtitle/{Episode.Slug}.{Language ?? ID.ToString()}"; - if (IsForced) - slug += "-forced"; + + string slug = string.IsNullOrEmpty(Language) + ? ID.ToString() + : $"{Episode.Slug}.{Language}{(IsForced ? "-forced" : "")}"; switch (Codec) { case "ass": diff --git a/Kyoo/Controllers/Repositories/CollectionRepository.cs b/Kyoo/Controllers/Repositories/CollectionRepository.cs index a4966407..72605d39 100644 --- a/Kyoo/Controllers/Repositories/CollectionRepository.cs +++ b/Kyoo/Controllers/Repositories/CollectionRepository.cs @@ -22,7 +22,7 @@ namespace Kyoo.Controllers public override async Task> Search(string query) { return await _database.Collections - .Where(x => EF.Functions.Like(x.Name, $"%{query}%")) + .Where(x => EF.Functions.ILike(x.Name, $"%{query}%")) .Take(20) .ToListAsync(); } diff --git a/Kyoo/Controllers/Repositories/EpisodeRepository.cs b/Kyoo/Controllers/Repositories/EpisodeRepository.cs index 6f9fd900..8c83be3a 100644 --- a/Kyoo/Controllers/Repositories/EpisodeRepository.cs +++ b/Kyoo/Controllers/Repositories/EpisodeRepository.cs @@ -38,7 +38,7 @@ namespace Kyoo.Controllers public override Task Get(string slug) { - Match match = Regex.Match(slug, @"(.*)-s(\d*)-e(\d*)"); + Match match = Regex.Match(slug, @"(?.*)-s(?\d*)-e(?\d*)"); if (!match.Success) return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == slug); @@ -57,7 +57,7 @@ namespace Kyoo.Controllers public override async Task> Search(string query) { return await _database.Episodes - .Where(x => EF.Functions.Like(x.Title, $"%{query}%")) + .Where(x => EF.Functions.ILike(x.Title, $"%{query}%")) .Take(20) .ToListAsync(); } diff --git a/Kyoo/Controllers/Repositories/GenreRepository.cs b/Kyoo/Controllers/Repositories/GenreRepository.cs index 9b2abcb1..dc891283 100644 --- a/Kyoo/Controllers/Repositories/GenreRepository.cs +++ b/Kyoo/Controllers/Repositories/GenreRepository.cs @@ -21,10 +21,10 @@ namespace Kyoo.Controllers } - public async Task> Search(string query) + public override async Task> Search(string query) { return await _database.Genres - .Where(genre => EF.Functions.Like(genre.Name, $"%{query}%")) + .Where(genre => EF.Functions.ILike(genre.Name, $"%{query}%")) .Take(20) .ToListAsync(); } @@ -57,7 +57,7 @@ namespace Kyoo.Controllers return Task.CompletedTask; } - public async Task Delete(Genre obj) + public override async Task Delete(Genre obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); diff --git a/Kyoo/Controllers/Repositories/LibraryRepository.cs b/Kyoo/Controllers/Repositories/LibraryRepository.cs index 4ae6757a..7766fe8e 100644 --- a/Kyoo/Controllers/Repositories/LibraryRepository.cs +++ b/Kyoo/Controllers/Repositories/LibraryRepository.cs @@ -9,54 +9,41 @@ using Microsoft.EntityFrameworkCore; namespace Kyoo.Controllers { - public class LibraryRepository : ILibraryRepository + public class LibraryRepository : LocalRepository, ILibraryRepository { private readonly DatabaseContext _database; private readonly IProviderRepository _providers; + protected override Expression> DefaultSort => x => x.ID; - public LibraryRepository(DatabaseContext database, IProviderRepository providers) + public LibraryRepository(DatabaseContext database, IProviderRepository providers) : base(database) { _database = database; _providers = providers; } - public void Dispose() + + public override void Dispose() { _database.Dispose(); + _providers.Dispose(); } - public ValueTask DisposeAsync() + public override async ValueTask DisposeAsync() { - return _database.DisposeAsync(); + await _database.DisposeAsync(); + await _providers.DisposeAsync(); } - public Task Get(int id) - { - return _database.Libraries.FirstOrDefaultAsync(x => x.ID == id); - } - - public Task Get(string slug) - { - return _database.Libraries.FirstOrDefaultAsync(x => x.Slug == slug); - } - - public async Task> Search(string query) + public override async Task> Search(string query) { return await _database.Libraries - .Where(x => EF.Functions.Like(x.Name, $"%{query}%")) + .Where(x => EF.Functions.ILike(x.Name, $"%{query}%")) .Take(20) .ToListAsync(); } - public async Task> GetAll(Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - return await _database.Libraries.ToListAsync(); - } - - public async Task Create(Library obj) + public override async Task Create(Library obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -74,73 +61,22 @@ namespace Kyoo.Controllers catch (DbUpdateException ex) { _database.DiscardChanges(); - if (Helper.IsDuplicateException(ex)) + if (IsDuplicateException(ex)) throw new DuplicatedItemException($"Trying to insert a duplicated library (slug {obj.Slug} already exists)."); throw; } return obj; } - - public async Task CreateIfNotExists(Library obj) - { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - Library old = await Get(obj.Slug); - if (old != null) - return old; - try - { - return await Create(obj); - } - catch (DuplicatedItemException) - { - old = await Get(obj.Slug); - if (old == null) - throw new SystemException("Unknown database state."); - return old; - } - } - - public async Task Edit(Library edited, bool resetOld) - { - if (edited == null) - throw new ArgumentNullException(nameof(edited)); - - Library old = await Get(edited.Name); - - if (old == null) - throw new ItemNotFound($"No library found with the name {edited.Name}."); - - if (resetOld) - Utility.Nullify(old); - Utility.Merge(old, edited); - await Validate(old); - await _database.SaveChangesAsync(); - return old; - } - - private async Task Validate(Library obj) + protected override async Task Validate(Library obj) { if (obj.ProviderLinks != null) foreach (ProviderLink link in obj.ProviderLinks) link.Provider = await _providers.CreateIfNotExists(link.Provider); } - public async Task Delete(int id) - { - Library obj = await Get(id); - await Delete(obj); - } - - public async Task Delete(string slug) - { - Library obj = await Get(slug); - await Delete(obj); - } - - public async Task Delete(Library obj) + public override async Task Delete(Library obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -154,23 +90,5 @@ namespace Kyoo.Controllers _database.Entry(entry).State = EntityState.Deleted; await _database.SaveChangesAsync(); } - - public async Task DeleteRange(IEnumerable objs) - { - foreach (Library obj in objs) - await Delete(obj); - } - - public async Task DeleteRange(IEnumerable ids) - { - foreach (int id in ids) - await Delete(id); - } - - public async Task DeleteRange(IEnumerable slugs) - { - foreach (string slug in slugs) - await Delete(slug); - } } } \ No newline at end of file diff --git a/Kyoo/Controllers/Repositories/PeopleRepository.cs b/Kyoo/Controllers/Repositories/PeopleRepository.cs index 7798cd8b..77b5f356 100644 --- a/Kyoo/Controllers/Repositories/PeopleRepository.cs +++ b/Kyoo/Controllers/Repositories/PeopleRepository.cs @@ -9,53 +9,40 @@ using Microsoft.EntityFrameworkCore; namespace Kyoo.Controllers { - public class PeopleRepository : IPeopleRepository + public class PeopleRepository : LocalRepository, IPeopleRepository { private readonly DatabaseContext _database; private readonly IProviderRepository _providers; + protected override Expression> DefaultSort => x => x.Name; - public PeopleRepository(DatabaseContext database, IProviderRepository providers) + public PeopleRepository(DatabaseContext database, IProviderRepository providers) : base(database) { _database = database; _providers = providers; } - - public void Dispose() + + + public override void Dispose() { _database.Dispose(); + _providers.Dispose(); } - public ValueTask DisposeAsync() + public override async ValueTask DisposeAsync() { - return _database.DisposeAsync(); + await _database.DisposeAsync(); + await _providers.DisposeAsync(); } - public Task Get(int id) - { - return _database.Peoples.FirstOrDefaultAsync(x => x.ID == id); - } - - public Task Get(string slug) - { - return _database.Peoples.FirstOrDefaultAsync(x => x.Slug == slug); - } - - public async Task> Search(string query) + public override async Task> Search(string query) { return await _database.Peoples - .Where(people => EF.Functions.Like(people.Name, $"%{query}%")) + .Where(people => EF.Functions.ILike(people.Name, $"%{query}%")) .Take(20) .ToListAsync(); } - public async Task> GetAll(Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - return await _database.Peoples.ToListAsync(); - } - - public async Task Create(People obj) + public override async Task Create(People obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -73,7 +60,7 @@ namespace Kyoo.Controllers catch (DbUpdateException ex) { _database.DiscardChanges(); - if (Helper.IsDuplicateException(ex)) + if (IsDuplicateException(ex)) throw new DuplicatedItemException($"Trying to insert a duplicated people (slug {obj.Slug} already exists)."); throw; } @@ -81,65 +68,14 @@ namespace Kyoo.Controllers return obj; } - public async Task CreateIfNotExists(People obj) - { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - People old = await Get(obj.Slug); - if (old != null) - return old; - try - { - return await Create(obj); - } - catch (DuplicatedItemException) - { - old = await Get(obj.Slug); - if (old == null) - throw new SystemException("Unknown database state."); - return old; - } - } - - public async Task Edit(People edited, bool resetOld) - { - if (edited == null) - throw new ArgumentNullException(nameof(edited)); - - People old = await Get(edited.Slug); - - if (old == null) - throw new ItemNotFound($"No people found with the slug {edited.Slug}."); - - if (resetOld) - Utility.Nullify(old); - Utility.Merge(old, edited); - await Validate(old); - await _database.SaveChangesAsync(); - return old; - } - - private async Task Validate(People obj) + protected override async Task Validate(People obj) { if (obj.ExternalIDs != null) foreach (MetadataID link in obj.ExternalIDs) link.Provider = await _providers.CreateIfNotExists(link.Provider); } - public async Task Delete(int id) - { - People obj = await Get(id); - await Delete(obj); - } - - public async Task Delete(string slug) - { - People obj = await Get(slug); - await Delete(obj); - } - - public async Task Delete(People obj) + public override async Task Delete(People obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -153,23 +89,5 @@ namespace Kyoo.Controllers _database.Entry(link).State = EntityState.Deleted; await _database.SaveChangesAsync(); } - - public async Task DeleteRange(IEnumerable objs) - { - foreach (People obj in objs) - await Delete(obj); - } - - public async Task DeleteRange(IEnumerable ids) - { - foreach (int id in ids) - await Delete(id); - } - - public async Task DeleteRange(IEnumerable slugs) - { - foreach (string slug in slugs) - await Delete(slug); - } } } \ No newline at end of file diff --git a/Kyoo/Controllers/Repositories/ProviderRepository.cs b/Kyoo/Controllers/Repositories/ProviderRepository.cs index be8f3989..f1477578 100644 --- a/Kyoo/Controllers/Repositories/ProviderRepository.cs +++ b/Kyoo/Controllers/Repositories/ProviderRepository.cs @@ -9,52 +9,26 @@ using Microsoft.EntityFrameworkCore; namespace Kyoo.Controllers { - public class ProviderRepository : IProviderRepository + public class ProviderRepository : LocalRepository, IProviderRepository { private readonly DatabaseContext _database; + protected override Expression> DefaultSort => x => x.Slug; - public ProviderRepository(DatabaseContext database) + public ProviderRepository(DatabaseContext database) : base(database) { _database = database; } - - public void Dispose() - { - _database.Dispose(); - } - public ValueTask DisposeAsync() - { - return _database.DisposeAsync(); - } - - public async Task Get(int id) - { - return await _database.Providers.FirstOrDefaultAsync(x => x.ID == id); - } - - public async Task Get(string slug) - { - return await _database.Providers.FirstOrDefaultAsync(x => x.Name == slug); - } - - public async Task> Search(string query) + public override async Task> Search(string query) { return await _database.Providers - .Where(x => EF.Functions.Like(x.Name, $"%{query}%")) + .Where(x => EF.Functions.ILike(x.Name, $"%{query}%")) .Take(20) .ToListAsync(); } - public async Task> GetAll(Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - return await _database.Providers.ToListAsync(); - } - - public async Task Create(ProviderID obj) + public override async Task Create(ProviderID obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -68,7 +42,7 @@ namespace Kyoo.Controllers catch (DbUpdateException ex) { _database.DiscardChanges(); - if (Helper.IsDuplicateException(ex)) + if (IsDuplicateException(ex)) throw new DuplicatedItemException($"Trying to insert a duplicated provider (name {obj.Name} already exists)."); throw; } @@ -76,57 +50,12 @@ namespace Kyoo.Controllers return obj; } - public async Task CreateIfNotExists(ProviderID obj) + protected override Task Validate(ProviderID ressource) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - ProviderID old = await Get(obj.Name); - if (old != null) - return old; - try - { - return await Create(obj); - } - catch (DuplicatedItemException) - { - old = await Get(obj.Name); - if (old == null) - throw new SystemException("Unknown database state."); - return old; - } + return Task.CompletedTask; } - public async Task Edit(ProviderID edited, bool resetOld) - { - if (edited == null) - throw new ArgumentNullException(nameof(edited)); - - ProviderID old = await Get(edited.Name); - - if (old == null) - throw new ItemNotFound($"No provider found with the name {edited.Name}."); - - if (resetOld) - Utility.Nullify(old); - Utility.Merge(old, edited); - await _database.SaveChangesAsync(); - return old; - } - - public async Task Delete(int id) - { - ProviderID obj = await Get(id); - await Delete(obj); - } - - public async Task Delete(string slug) - { - ProviderID obj = await Get(slug); - await Delete(obj); - } - - public async Task Delete(ProviderID obj) + public override async Task Delete(ProviderID obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -135,23 +64,5 @@ namespace Kyoo.Controllers // TODO handle ExternalID deletion when they refer to this providerID. await _database.SaveChangesAsync(); } - - public async Task DeleteRange(IEnumerable objs) - { - foreach (ProviderID obj in objs) - await Delete(obj); - } - - public async Task DeleteRange(IEnumerable ids) - { - foreach (int id in ids) - await Delete(id); - } - - public async Task DeleteRange(IEnumerable slugs) - { - foreach (string slug in slugs) - await Delete(slug); - } } } \ No newline at end of file diff --git a/Kyoo/Controllers/Repositories/SeasonRepository.cs b/Kyoo/Controllers/Repositories/SeasonRepository.cs index 045599b8..8ecb92ad 100644 --- a/Kyoo/Controllers/Repositories/SeasonRepository.cs +++ b/Kyoo/Controllers/Repositories/SeasonRepository.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Kyoo.Models; using Kyoo.Models.Exceptions; @@ -9,44 +10,44 @@ using Microsoft.EntityFrameworkCore; namespace Kyoo.Controllers { - public class SeasonRepository : ISeasonRepository + public class SeasonRepository : LocalRepository, ISeasonRepository { private readonly DatabaseContext _database; private readonly IProviderRepository _providers; private readonly IEpisodeRepository _episodes; + protected override Expression> DefaultSort => x => x.SeasonNumber; public SeasonRepository(DatabaseContext database, IProviderRepository providers, IEpisodeRepository episodes) + : base(database) { _database = database; _providers = providers; _episodes = episodes; } - - public void Dispose() + + + public override void Dispose() { _database.Dispose(); + _providers.Dispose(); + _episodes.Dispose(); } - public ValueTask DisposeAsync() + public override async ValueTask DisposeAsync() { - return _database.DisposeAsync(); - } - - public Task Get(int id) - { - return _database.Seasons.FirstOrDefaultAsync(x => x.ID == id); + await _database.DisposeAsync(); + await _providers.DisposeAsync(); + await _episodes.DisposeAsync(); } - public Task Get(string slug) + public override Task Get(string slug) { - int index = slug.IndexOf("-s", StringComparison.Ordinal); - if (index == -1) - throw new InvalidOperationException("Invalid season slug. Format: {showSlug}-s{seasonNumber}"); - string showSlug = slug.Substring(0, index); - if (!int.TryParse(slug.Substring(index + 2), out int seasonNumber)) - throw new InvalidOperationException("Invalid season slug. Format: {showSlug}-s{seasonNumber}"); - return Get(showSlug, seasonNumber); + Match match = Regex.Match(slug, @"(?.*)-s(?\d*)"); + + if (!match.Success) + throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}"); + return Get(match.Groups["show"].Value, int.Parse(match.Groups["season"].Value)); } public Task Get(string showSlug, int seasonNumber) @@ -55,22 +56,15 @@ namespace Kyoo.Controllers && x.SeasonNumber == seasonNumber); } - public async Task> Search(string query) + public override async Task> Search(string query) { return await _database.Seasons - .Where(x => EF.Functions.Like(x.Title, $"%{query}%")) + .Where(x => EF.Functions.ILike(x.Title, $"%{query}%")) .Take(20) .ToListAsync(); } - - public async Task> GetAll(Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - return await _database.Seasons.ToListAsync(); - } - - public async Task Create(Season obj) + + public override async Task Create(Season obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -88,55 +82,15 @@ namespace Kyoo.Controllers catch (DbUpdateException ex) { _database.DiscardChanges(); - if (Helper.IsDuplicateException(ex)) + if (IsDuplicateException(ex)) throw new DuplicatedItemException($"Trying to insert a duplicated season (slug {obj.Slug} already exists)."); throw; } return obj; } - - public async Task CreateIfNotExists(Season obj) - { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - Season old = await Get(obj.Slug); - if (old != null) - return old; - try - { - return await Create(obj); - } - catch (DuplicatedItemException) - { - old = await Get(obj.Slug); - if (old == null) - throw new SystemException("Unknown database state."); - return old; - } - } - - public async Task Edit(Season edited, bool resetOld) - { - if (edited == null) - throw new ArgumentNullException(nameof(edited)); - - Season old = await Get(edited.Slug); - - if (old == null) - throw new ItemNotFound($"No season found with the slug {edited.Slug}."); - - if (resetOld) - Utility.Nullify(old); - Utility.Merge(old, edited); - - await Validate(old); - await _database.SaveChangesAsync(); - return old; - } - - private async Task Validate(Season obj) + protected override async Task Validate(Season obj) { if (obj.ShowID <= 0) throw new InvalidOperationException($"Can't store a season not related to any show (showID: {obj.ShowID})."); @@ -158,25 +112,13 @@ namespace Kyoo.Controllers return await _database.Seasons.Where(x => x.Show.Slug == showSlug).ToListAsync(); } - public async Task Delete(int id) - { - Season obj = await Get(id); - await Delete(obj); - } - - public async Task Delete(string slug) - { - Season obj = await Get(slug); - await Delete(obj); - } - public async Task Delete(string showSlug, int seasonNumber) { Season obj = await Get(showSlug, seasonNumber); await Delete(obj); } - public async Task Delete(Season obj) + public override async Task Delete(Season obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -192,23 +134,5 @@ namespace Kyoo.Controllers if (obj.Episodes != null) await _episodes.DeleteRange(obj.Episodes); } - - public async Task DeleteRange(IEnumerable objs) - { - foreach (Season obj in objs) - await Delete(obj); - } - - public async Task DeleteRange(IEnumerable ids) - { - foreach (int id in ids) - await Delete(id); - } - - public async Task DeleteRange(IEnumerable slugs) - { - foreach (string slug in slugs) - await Delete(slug); - } } } \ No newline at end of file diff --git a/Kyoo/Controllers/Repositories/ShowRepository.cs b/Kyoo/Controllers/Repositories/ShowRepository.cs index db1b7b83..b0335786 100644 --- a/Kyoo/Controllers/Repositories/ShowRepository.cs +++ b/Kyoo/Controllers/Repositories/ShowRepository.cs @@ -3,14 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; -using Kyoo.CommonApi; using Kyoo.Models; using Kyoo.Models.Exceptions; using Microsoft.EntityFrameworkCore; namespace Kyoo.Controllers { - public class ShowRepository : IShowRepository + public class ShowRepository : LocalRepository, IShowRepository { private readonly DatabaseContext _database; private readonly IStudioRepository _studios; @@ -19,6 +18,7 @@ namespace Kyoo.Controllers private readonly IProviderRepository _providers; private readonly ISeasonRepository _seasons; private readonly IEpisodeRepository _episodes; + protected override Expression> DefaultSort => x => x.Title; public ShowRepository(DatabaseContext database, IStudioRepository studios, @@ -27,6 +27,7 @@ namespace Kyoo.Controllers IProviderRepository providers, ISeasonRepository seasons, IEpisodeRepository episodes) + : base(database) { _database = database; _studios = studios; @@ -36,70 +37,39 @@ namespace Kyoo.Controllers _seasons = seasons; _episodes = episodes; } - - public void Dispose() + + public override void Dispose() { _database.Dispose(); _studios.Dispose(); + _people.Dispose(); + _genres.Dispose(); + _providers.Dispose(); + _seasons.Dispose(); + _episodes.Dispose(); } - public async ValueTask DisposeAsync() + public override async ValueTask DisposeAsync() { - await Task.WhenAll(_database.DisposeAsync().AsTask(), _studios.DisposeAsync().AsTask()); - } - - public Task Get(int id) - { - return _database.Shows.FirstOrDefaultAsync(x => x.ID == id); - } - - public Task Get(string slug) - { - return _database.Shows.FirstOrDefaultAsync(x => x.Slug == slug); + await _database.DisposeAsync(); + await _studios.DisposeAsync(); + await _people.DisposeAsync(); + await _genres.DisposeAsync(); + await _providers.DisposeAsync(); + await _seasons.DisposeAsync(); + await _episodes.DisposeAsync(); } - public Task GetByPath(string path) - { - return _database.Shows.FirstOrDefaultAsync(x => x.Path == path); - } - - public async Task> Search(string query) + public override async Task> Search(string query) { return await _database.Shows - .FromSqlInterpolated($@"SELECT * FROM Shows WHERE 'Shows.Title' LIKE {$"%{query}%"} - OR 'Shows.Aliases' LIKE {$"%{query}%"}") + .Where(x => EF.Functions.ILike(x.Title, $"%{query}%") + /*|| EF.Functions.ILike(x.Aliases, $"%{query}%")*/) .Take(20) .ToListAsync(); } - public async Task> GetAll(Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - IQueryable query = _database.Shows; - - if (where != null) - query = query.Where(where); - - Expression> sortKey = sort.Key ?? (x => x.Title); - query = sort.Descendant ? query.OrderByDescending(sortKey) : query.OrderBy(sortKey); - - if (limit.AfterID != 0) - { - Show after = await Get(limit.AfterID); - object afterObj = sortKey.Compile()(after); - query = query.Where(Expression.Lambda>( - ApiHelper.StringCompatibleExpression(Expression.GreaterThan, sortKey.Body, Expression.Constant(afterObj)), - (ParameterExpression)((MemberExpression)sortKey.Body).Expression - )); - } - if (limit.Count > 0) - query = query.Take(limit.Count); - - return await query.ToListAsync(); - } - - public async Task Create(Show obj) + public override async Task Create(Show obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -123,7 +93,7 @@ namespace Kyoo.Controllers catch (DbUpdateException ex) { _database.DiscardChanges(); - if (Helper.IsDuplicateException(ex)) + if (IsDuplicateException(ex)) throw new DuplicatedItemException($"Trying to insert a duplicated show (slug {obj.Slug} already exists)."); throw; } @@ -131,46 +101,7 @@ namespace Kyoo.Controllers return obj; } - public async Task CreateIfNotExists(Show obj) - { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - Show old = await Get(obj.Slug); - if (old != null) - return old; - try - { - return await Create(obj); - } - catch (DuplicatedItemException) - { - old = await Get(obj.Slug); - if (old == null) - throw new SystemException("Unknown database state."); - return old; - } - } - - public async Task Edit(Show edited, bool resetOld) - { - if (edited == null) - throw new ArgumentNullException(nameof(edited)); - - Show old = await Get(edited.Slug); - - if (old == null) - throw new ItemNotFound($"No show found with the slug {edited.Slug}."); - - if (resetOld) - Utility.Nullify(old); - Utility.Merge(old, edited); - await Validate(old); - await _database.SaveChangesAsync(); - return old; - } - - private async Task Validate(Show obj) + protected override async Task Validate(Show obj) { if (obj.Studio != null) obj.Studio = await _studios.CreateIfNotExists(obj.Studio); @@ -210,20 +141,8 @@ namespace Kyoo.Controllers await _database.SaveChangesAsync(); } - - public async Task Delete(int id) - { - Show obj = await Get(id); - await Delete(obj); - } - - public async Task Delete(string slug) - { - Show obj = await Get(slug); - await Delete(obj); - } - public async Task Delete(Show obj) + public override async Task Delete(Show obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -258,23 +177,5 @@ namespace Kyoo.Controllers if (obj.Episodes != null) await _episodes.DeleteRange(obj.Episodes); } - - public async Task DeleteRange(IEnumerable objs) - { - foreach (Show obj in objs) - await Delete(obj); - } - - public async Task DeleteRange(IEnumerable ids) - { - foreach (int id in ids) - await Delete(id); - } - - public async Task DeleteRange(IEnumerable slugs) - { - foreach (string slug in slugs) - await Delete(slug); - } } } \ No newline at end of file diff --git a/Kyoo/Controllers/Repositories/StudioRepository.cs b/Kyoo/Controllers/Repositories/StudioRepository.cs index 3dc06439..299eb712 100644 --- a/Kyoo/Controllers/Repositories/StudioRepository.cs +++ b/Kyoo/Controllers/Repositories/StudioRepository.cs @@ -9,52 +9,26 @@ using Microsoft.EntityFrameworkCore; namespace Kyoo.Controllers { - public class StudioRepository : IStudioRepository + public class StudioRepository : LocalRepository, IStudioRepository { private readonly DatabaseContext _database; + protected override Expression> DefaultSort => x => x.Name; - public StudioRepository(DatabaseContext database) + public StudioRepository(DatabaseContext database) : base(database) { _database = database; } - public void Dispose() - { - _database.Dispose(); - } - - public ValueTask DisposeAsync() - { - return _database.DisposeAsync(); - } - - public async Task Get(int id) - { - return await _database.Studios.FirstOrDefaultAsync(x => x.ID == id); - } - - public async Task Get(string slug) - { - return await _database.Studios.FirstOrDefaultAsync(x => x.Slug == slug); - } - - public async Task> Search(string query) + public override async Task> Search(string query) { return await _database.Studios - .Where(x => EF.Functions.Like(x.Name, $"%{query}%")) + .Where(x => EF.Functions.ILike(x.Name, $"%{query}%")) .Take(20) .ToListAsync(); } - public async Task> GetAll(Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - return await _database.Studios.ToListAsync(); - } - - public async Task Create(Studio obj) + public override async Task Create(Studio obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -68,64 +42,19 @@ namespace Kyoo.Controllers catch (DbUpdateException ex) { _database.DiscardChanges(); - if (Helper.IsDuplicateException(ex)) + if (IsDuplicateException(ex)) throw new DuplicatedItemException($"Trying to insert a duplicated studio (slug {obj.Slug} already exists)."); throw; } return obj; } - - public async Task CreateIfNotExists(Studio obj) + + protected override Task Validate(Studio ressource) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - Studio old = await Get(obj.Slug); - if (old != null) - return old; - try - { - return await Create(obj); - } - catch (DuplicatedItemException) - { - old = await Get(obj.Slug); - if (old == null) - throw new SystemException("Unknown database state."); - return old; - } - } - - public async Task Edit(Studio edited, bool resetOld) - { - if (edited == null) - throw new ArgumentNullException(nameof(edited)); - - Studio old = await Get(edited.Name); - - if (old == null) - throw new ItemNotFound($"No studio found with the name {edited.Name}."); - - if (resetOld) - Utility.Nullify(old); - Utility.Merge(old, edited); - await _database.SaveChangesAsync(); - return old; - } - - public async Task Delete(int id) - { - Studio obj = await Get(id); - await Delete(obj); - } - - public async Task Delete(string slug) - { - Studio obj = await Get(slug); - await Delete(obj); + return Task.CompletedTask; } - public async Task Delete(Studio obj) + public override async Task Delete(Studio obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -137,23 +66,5 @@ namespace Kyoo.Controllers show.StudioID = null; await _database.SaveChangesAsync(); } - - public async Task DeleteRange(IEnumerable objs) - { - foreach (Studio obj in objs) - await Delete(obj); - } - - public async Task DeleteRange(IEnumerable ids) - { - foreach (int id in ids) - await Delete(id); - } - - public async Task DeleteRange(IEnumerable slugs) - { - foreach (string slug in slugs) - await Delete(slug); - } } } \ No newline at end of file diff --git a/Kyoo/Controllers/Repositories/TrackRepository.cs b/Kyoo/Controllers/Repositories/TrackRepository.cs index 5362c63d..01334f2f 100644 --- a/Kyoo/Controllers/Repositories/TrackRepository.cs +++ b/Kyoo/Controllers/Repositories/TrackRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Kyoo.Models; using Kyoo.Models.Exceptions; @@ -8,34 +9,39 @@ using Microsoft.EntityFrameworkCore; namespace Kyoo.Controllers { - public class TrackRepository : ITrackRepository + public class TrackRepository : LocalRepository, ITrackRepository { private readonly DatabaseContext _database; + protected override Expression> DefaultSort => x => x.ID; - public TrackRepository(DatabaseContext database) + public TrackRepository(DatabaseContext database) : base(database) { _database = database; } - - public void Dispose() - { - _database.Dispose(); - } - public ValueTask DisposeAsync() + public override Task Get(string slug) { - return _database.DisposeAsync(); - } - - public async Task Get(int id) - { - return await _database.Tracks.FirstOrDefaultAsync(x => x.ID == id); - } - - public Task Get(string slug) - { - throw new InvalidOperationException("Tracks do not support the get by slug method."); + Match match = Regex.Match(slug, + @"(?.*)-s(?\d*)-e(?\d*).(?.{0,3})(?-forced)?(\..*)?"); + + if (!match.Success) + { + if (int.TryParse(slug, out int id)) + return Get(id); + throw new ArgumentException("Invalid track slug. Format: {episodeSlug}.{language}[-forced][.{extension}]"); + } + + string showSlug = match.Groups["show"].Value; + int seasonNumber = int.Parse(match.Groups["season"].Value); + int episodeNumber = int.Parse(match.Groups["episode"].Value); + string language = match.Groups["language"].Value; + bool forced = match.Groups["forced"].Success; + return _database.Tracks.FirstOrDefaultAsync(x => x.Episode.Show.Slug == showSlug + && x.Episode.SeasonNumber == seasonNumber + && x.Episode.EpisodeNumber == episodeNumber + && x.Language == language + && x.IsForced == forced); } public Task Get(int episodeID, string languageTag, bool isForced) @@ -45,19 +51,12 @@ namespace Kyoo.Controllers && x.IsForced == isForced); } - public Task> Search(string query) + public override Task> Search(string query) { throw new InvalidOperationException("Tracks do not support the search method."); } - public async Task> GetAll(Expression> where = null, - Sort sort = default, - Pagination limit = default) - { - return await _database.Tracks.ToListAsync(); - } - - public async Task Create(Track obj) + public override async Task Create(Track obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -74,48 +73,19 @@ namespace Kyoo.Controllers catch (DbUpdateException ex) { _database.DiscardChanges(); - if (Helper.IsDuplicateException(ex)) + if (IsDuplicateException(ex)) throw new DuplicatedItemException($"Trying to insert a duplicated track (slug {obj.Slug} already exists)."); throw; } return obj; } - public Task CreateIfNotExists(Track obj) + protected override Task Validate(Track ressource) { - return Create(obj); - } - - public async Task Edit(Track edited, bool resetOld) - { - if (edited == null) - throw new ArgumentNullException(nameof(edited)); - - Track old = await Get(edited.ID); - - if (old == null) - throw new ItemNotFound($"No track found with the ID {edited.ID}."); - - if (resetOld) - Utility.Nullify(old); - Utility.Merge(old, edited); - await _database.SaveChangesAsync(); - return old; - } - - public async Task Delete(int id) - { - Track obj = await Get(id); - await Delete(obj); - } - - public async Task Delete(string slug) - { - Track obj = await Get(slug); - await Delete(obj); + return Task.CompletedTask; } - public async Task Delete(Track obj) + public override async Task Delete(Track obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); @@ -123,23 +93,5 @@ namespace Kyoo.Controllers _database.Entry(obj).State = EntityState.Deleted; await _database.SaveChangesAsync(); } - - public async Task DeleteRange(IEnumerable objs) - { - foreach (Track obj in objs) - await Delete(obj); - } - - public async Task DeleteRange(IEnumerable ids) - { - foreach (int id in ids) - await Delete(id); - } - - public async Task DeleteRange(IEnumerable slugs) - { - foreach (string slug in slugs) - await Delete(slug); - } } } \ No newline at end of file