diff --git a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
index 56b9b26b..df64bbd7 100644
--- a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
+++ b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
@@ -249,7 +249,7 @@ namespace Kyoo.Abstractions.Controllers
/// The id of the show
/// The season's number
/// The season found
- Task GetOrDefault(int showID, int seasonNumber);
+ Task GetOrDefault(int showID, int seasonNumber);
///
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
@@ -257,7 +257,7 @@ namespace Kyoo.Abstractions.Controllers
/// The slug of the show
/// The season's number
/// The season found
- Task GetOrDefault(string showSlug, int seasonNumber);
+ Task GetOrDefault(string showSlug, int seasonNumber);
}
///
@@ -294,7 +294,7 @@ namespace Kyoo.Abstractions.Controllers
/// The season's number
/// The episode's number
/// The episode found
- Task GetOrDefault(int showID, int seasonNumber, int episodeNumber);
+ Task GetOrDefault(int showID, int seasonNumber, int episodeNumber);
///
/// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found.
@@ -303,7 +303,7 @@ namespace Kyoo.Abstractions.Controllers
/// The season's number
/// The episode's number
/// The episode found
- Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
+ Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
///
/// Get a episode from it's showID and it's absolute number.
diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs b/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs
index e34efcd1..f08720b4 100644
--- a/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs
+++ b/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs
@@ -46,7 +46,7 @@ namespace Kyoo.Abstractions.Controllers
///
/// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
///
- public By(Expression> key, bool desendant = false)
+ public By(Expression> key, bool desendant = false)
: this(Utility.GetPropertyName(key), desendant) { }
}
diff --git a/back/src/Kyoo.Core/Controllers/IdentifierRouteConstraint.cs b/back/src/Kyoo.Core/Controllers/IdentifierRouteConstraint.cs
index cda79146..c8a96c75 100644
--- a/back/src/Kyoo.Core/Controllers/IdentifierRouteConstraint.cs
+++ b/back/src/Kyoo.Core/Controllers/IdentifierRouteConstraint.cs
@@ -28,8 +28,8 @@ namespace Kyoo.Core.Controllers
public class IdentifierRouteConstraint : IRouteConstraint
{
///
- public bool Match(HttpContext httpContext,
- IRouter route,
+ public bool Match(HttpContext? httpContext,
+ IRouter? route,
string routeKey,
RouteValueDictionary values,
RouteDirection routeDirection)
diff --git a/back/src/Kyoo.Core/Controllers/LibraryManager.cs b/back/src/Kyoo.Core/Controllers/LibraryManager.cs
index 3d3f77bf..664f56bb 100644
--- a/back/src/Kyoo.Core/Controllers/LibraryManager.cs
+++ b/back/src/Kyoo.Core/Controllers/LibraryManager.cs
@@ -74,15 +74,15 @@ namespace Kyoo.Core.Controllers
public LibraryManager(IEnumerable repositories)
{
_repositories = repositories.ToArray();
- LibraryItemRepository = GetRepository() as ILibraryItemRepository;
- CollectionRepository = GetRepository() as ICollectionRepository;
- MovieRepository = GetRepository() as IMovieRepository;
- ShowRepository = GetRepository() as IShowRepository;
- SeasonRepository = GetRepository() as ISeasonRepository;
- EpisodeRepository = GetRepository() as IEpisodeRepository;
- PeopleRepository = GetRepository() as IPeopleRepository;
- StudioRepository = GetRepository() as IStudioRepository;
- UserRepository = GetRepository() as IUserRepository;
+ LibraryItemRepository = (ILibraryItemRepository)GetRepository();
+ CollectionRepository = (ICollectionRepository)GetRepository();
+ MovieRepository = (IMovieRepository)GetRepository();
+ ShowRepository = (IShowRepository)GetRepository();
+ SeasonRepository = (ISeasonRepository)GetRepository();
+ EpisodeRepository = (IEpisodeRepository)GetRepository();
+ PeopleRepository = (IPeopleRepository)GetRepository();
+ StudioRepository = (IStudioRepository)GetRepository();
+ UserRepository = (IUserRepository)GetRepository();
}
///
@@ -140,46 +140,46 @@ namespace Kyoo.Core.Controllers
}
///
- public async Task GetOrDefault(int id)
+ public async Task GetOrDefault(int id)
where T : class, IResource
{
return await GetRepository().GetOrDefault(id);
}
///
- public async Task GetOrDefault(string slug)
+ public async Task GetOrDefault(string slug)
where T : class, IResource
{
return await GetRepository().GetOrDefault(slug);
}
///
- public async Task GetOrDefault(Expression> where, Sort sortBy)
+ public async Task GetOrDefault(Expression> where, Sort? sortBy)
where T : class, IResource
{
return await GetRepository().GetOrDefault(where, sortBy);
}
///
- public async Task GetOrDefault(int showID, int seasonNumber)
+ public async Task GetOrDefault(int showID, int seasonNumber)
{
return await SeasonRepository.GetOrDefault(showID, seasonNumber);
}
///
- public async Task GetOrDefault(string showSlug, int seasonNumber)
+ public async Task GetOrDefault(string showSlug, int seasonNumber)
{
return await SeasonRepository.GetOrDefault(showSlug, seasonNumber);
}
///
- public async Task GetOrDefault(int showID, int seasonNumber, int episodeNumber)
+ public async Task GetOrDefault(int showID, int seasonNumber, int episodeNumber)
{
return await EpisodeRepository.GetOrDefault(showID, seasonNumber, episodeNumber);
}
///
- public async Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
+ public async Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
{
return await EpisodeRepository.GetOrDefault(showSlug, seasonNumber, episodeNumber);
}
@@ -238,7 +238,7 @@ namespace Kyoo.Core.Controllers
if (obj == null)
throw new ArgumentNullException(nameof(obj));
- object existingValue = obj.GetType()
+ object? existingValue = obj.GetType()
.GetProperties()
.FirstOrDefault(x => string.Equals(x.Name, memberName, StringComparison.InvariantCultureIgnoreCase))
?.GetValue(obj);
@@ -248,11 +248,11 @@ namespace Kyoo.Core.Controllers
return (obj, member: memberName) switch
{
(Collection c, nameof(Collection.Shows)) => ShowRepository
- .GetAll(x => x.Collections.Any(y => y.Id == obj.Id))
+ .GetAll(x => x.Collections!.Any(y => y.Id == obj.Id))
.Then(x => c.Shows = x),
(Collection c, nameof(Collection.Movies)) => MovieRepository
- .GetAll(x => x.Collections.Any(y => y.Id == obj.Id))
+ .GetAll(x => x.Collections!.Any(y => y.Id == obj.Id))
.Then(x => c.Movies = x),
@@ -261,11 +261,11 @@ namespace Kyoo.Core.Controllers
.Then(x => m.People = x),
(Movie m, nameof(Movie.Collections)) => CollectionRepository
- .GetAll(x => x.Movies.Any(y => y.Id == obj.Id))
+ .GetAll(x => x.Movies!.Any(y => y.Id == obj.Id))
.Then(x => m.Collections = x),
(Movie m, nameof(Movie.Studio)) => StudioRepository
- .GetOrDefault(x => x.Movies.Any(y => y.Id == obj.Id))
+ .GetOrDefault(x => x.Movies!.Any(y => y.Id == obj.Id))
.Then(x =>
{
m.Studio = x;
@@ -278,21 +278,21 @@ namespace Kyoo.Core.Controllers
.Then(x => s.People = x),
(Show s, nameof(Show.Seasons)) => _SetRelation(s,
- SeasonRepository.GetAll(x => x.Show.Id == obj.Id),
+ SeasonRepository.GetAll(x => x.Show!.Id == obj.Id),
(x, y) => x.Seasons = y,
(x, y) => { x.Show = y; x.ShowId = y.Id; }),
(Show s, nameof(Show.Episodes)) => _SetRelation(s,
- EpisodeRepository.GetAll(x => x.Show.Id == obj.Id),
+ EpisodeRepository.GetAll(x => x.Show!.Id == obj.Id),
(x, y) => x.Episodes = y,
(x, y) => { x.Show = y; x.ShowId = y.Id; }),
(Show s, nameof(Show.Collections)) => CollectionRepository
- .GetAll(x => x.Shows.Any(y => y.Id == obj.Id))
+ .GetAll(x => x.Shows!.Any(y => y.Id == obj.Id))
.Then(x => s.Collections = x),
(Show s, nameof(Show.Studio)) => StudioRepository
- .GetOrDefault(x => x.Shows.Any(y => y.Id == obj.Id))
+ .GetOrDefault(x => x.Shows!.Any(y => y.Id == obj.Id))
.Then(x =>
{
s.Studio = x;
@@ -301,12 +301,12 @@ namespace Kyoo.Core.Controllers
(Season s, nameof(Season.Episodes)) => _SetRelation(s,
- EpisodeRepository.GetAll(x => x.Season.Id == obj.Id),
+ EpisodeRepository.GetAll(x => x.Season!.Id == obj.Id),
(x, y) => x.Episodes = y,
(x, y) => { x.Season = y; x.SeasonId = y.Id; }),
(Season s, nameof(Season.Show)) => ShowRepository
- .GetOrDefault(x => x.Seasons.Any(y => y.Id == obj.Id))
+ .GetOrDefault(x => x.Seasons!.Any(y => y.Id == obj.Id))
.Then(x =>
{
s.Show = x;
@@ -315,7 +315,7 @@ namespace Kyoo.Core.Controllers
(Episode e, nameof(Episode.Show)) => ShowRepository
- .GetOrDefault(x => x.Episodes.Any(y => y.Id == obj.Id))
+ .GetOrDefault(x => x.Episodes!.Any(y => y.Id == obj.Id))
.Then(x =>
{
e.Show = x;
@@ -323,7 +323,7 @@ namespace Kyoo.Core.Controllers
}),
(Episode e, nameof(Episode.Season)) => SeasonRepository
- .GetOrDefault(x => x.Episodes.Any(y => y.Id == e.Id))
+ .GetOrDefault(x => x.Episodes!.Any(y => y.Id == e.Id))
.Then(x =>
{
e.Season = x;
@@ -344,11 +344,11 @@ namespace Kyoo.Core.Controllers
(Studio s, nameof(Studio.Shows)) => ShowRepository
- .GetAll(x => x.Studio.Id == obj.Id)
+ .GetAll(x => x.Studio!.Id == obj.Id)
.Then(x => s.Shows = x),
(Studio s, nameof(Studio.Movies)) => MovieRepository
- .GetAll(x => x.Studio.Id == obj.Id)
+ .GetAll(x => x.Studio!.Id == obj.Id)
.Then(x => s.Movies = x),
@@ -362,51 +362,51 @@ namespace Kyoo.Core.Controllers
///
public Task> GetPeopleFromShow(int showID,
- Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
return PeopleRepository.GetFromShow(showID, where, sort, limit);
}
///
public Task> GetPeopleFromShow(string showSlug,
- Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
return PeopleRepository.GetFromShow(showSlug, where, sort, limit);
}
///
public Task> GetRolesFromPeople(int id,
- Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
return PeopleRepository.GetFromPeople(id, where, sort, limit);
}
///
public Task> GetRolesFromPeople(string slug,
- Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
return PeopleRepository.GetFromPeople(slug, where, sort, limit);
}
///
- public Task> GetAll(Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ public Task> GetAll(Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
where T : class, IResource
{
return GetRepository().GetAll(where, sort, limit);
}
///
- public Task GetCount(Expression> where = null)
+ public Task GetCount(Expression>? where = null)
where T : class, IResource
{
return GetRepository().GetCount(where);
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
index 933c2bb7..153c855d 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
@@ -77,7 +77,7 @@ namespace Kyoo.Core.Controllers
}
///
- public Task GetOrDefault(int showID, int seasonNumber, int episodeNumber)
+ public Task GetOrDefault(int showID, int seasonNumber, int episodeNumber)
{
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID
&& x.SeasonNumber == seasonNumber
@@ -85,9 +85,9 @@ namespace Kyoo.Core.Controllers
}
///
- public Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
+ public Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
{
- return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
+ return _database.Episodes.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug
&& x.SeasonNumber == seasonNumber
&& x.EpisodeNumber == episodeNumber).Then(SetBackingImage);
}
@@ -95,7 +95,7 @@ namespace Kyoo.Core.Controllers
///
public async Task Get(int showID, int seasonNumber, int episodeNumber)
{
- Episode ret = await GetOrDefault(showID, seasonNumber, episodeNumber);
+ Episode? ret = await GetOrDefault(showID, seasonNumber, episodeNumber);
if (ret == null)
throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showID}.");
return ret;
@@ -104,24 +104,30 @@ namespace Kyoo.Core.Controllers
///
public async Task Get(string showSlug, int seasonNumber, int episodeNumber)
{
- Episode ret = await GetOrDefault(showSlug, seasonNumber, episodeNumber);
+ Episode? ret = await GetOrDefault(showSlug, seasonNumber, episodeNumber);
if (ret == null)
throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showSlug}.");
return ret;
}
///
- public Task GetAbsolute(int showID, int absoluteNumber)
+ public async Task GetAbsolute(int showID, int absoluteNumber)
{
- return _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID
+ Episode? ret = await _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID
&& x.AbsoluteNumber == absoluteNumber).Then(SetBackingImage);
+ if (ret == null)
+ throw new ItemNotFoundException();
+ return ret;
}
///
- public Task GetAbsolute(string showSlug, int absoluteNumber)
+ public async Task GetAbsolute(string showSlug, int absoluteNumber)
{
- return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
+ Episode? ret = await _database.Episodes.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug
&& x.AbsoluteNumber == absoluteNumber).Then(SetBackingImage);
+ if (ret == null)
+ throw new ItemNotFoundException();
+ return ret;
}
///
@@ -131,13 +137,13 @@ namespace Kyoo.Core.Controllers
_database.Episodes
.Include(x => x.Show)
.Where(x => x.EpisodeNumber != null || x.AbsoluteNumber != null)
- .Where(_database.Like(x => x.Name, $"%{query}%"))
+ .Where(_database.Like(x => x.Name!, $"%{query}%"))
)
.Take(20)
.ToListAsync();
foreach (Episode ep in ret)
{
- ep.Show.Episodes = null;
+ ep.Show!.Episodes = null;
SetBackingImage(ep);
}
return ret;
@@ -152,7 +158,7 @@ namespace Kyoo.Core.Controllers
await _database.SaveChangesAsync(() =>
obj.SeasonNumber != null && obj.EpisodeNumber != null
? Get(obj.ShowId, obj.SeasonNumber.Value, obj.EpisodeNumber.Value)
- : GetAbsolute(obj.ShowId, obj.AbsoluteNumber.Value));
+ : GetAbsolute(obj.ShowId, obj.AbsoluteNumber!.Value));
OnResourceCreated(obj);
return obj;
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
index 5c9ed0a3..a8b50d66 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
@@ -85,7 +85,7 @@ namespace Kyoo.Core.Controllers
/// The query to sort.
/// How to sort the query
/// The newly sorted query.
- protected IOrderedQueryable Sort(IQueryable query, Sort sortBy = null)
+ protected IOrderedQueryable Sort(IQueryable query, Sort? sortBy = null)
{
sortBy ??= DefaultSort;
@@ -138,7 +138,7 @@ namespace Kyoo.Core.Controllers
: (greaterThan ? Expression.GreaterThan : Expression.LessThan);
}
- private record SortIndicator(string key, bool desc, string? seed);
+ private record SortIndicator(string Key, bool Desc, string? Seed);
///
/// Create a filter (where) expression on the query to skip everything before/after the referenceID.
@@ -158,7 +158,7 @@ namespace Kyoo.Core.Controllers
/// True if the following page should be returned, false for the previous.
/// An expression ready to be added to a Where close of a sorted query to handle the AfterID
protected Expression> KeysetPaginate(
- Sort sort,
+ Sort? sort,
T reference,
bool next = true)
{
@@ -170,7 +170,7 @@ namespace Kyoo.Core.Controllers
void GetRandomSortKeys(string seed, out Expression left, out Expression right)
{
- MethodInfo concat = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) });
+ MethodInfo concat = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) })!;
Expression id = Expression.Call(Expression.Property(x, "ID"), nameof(int.ToString), null);
Expression xrng = Expression.Call(concat, Expression.Constant(seed), id);
right = Expression.Call(typeof(DatabaseContext), nameof(DatabaseContext.MD5), null, Expression.Constant($"{seed}{reference.Id}"));
@@ -193,14 +193,14 @@ namespace Kyoo.Core.Controllers
IEnumerable sorts = GetSortsBy(sort)
.Append(new SortIndicator("Id", false, null));
- BinaryExpression filter = null;
+ BinaryExpression? filter = null;
List previousSteps = new();
// TODO: Add an outer query >= for perf
// PERF: See https://use-the-index-luke.com/sql/partial-results/fetch-next-page#sb-equivalent-logic
foreach ((string key, bool desc, string? seed) in sorts)
{
- BinaryExpression compare = null;
- PropertyInfo property = key != "random"
+ BinaryExpression? compare = null;
+ PropertyInfo? property = key != "random"
? typeof(T).GetProperty(key)
: null;
@@ -268,7 +268,7 @@ namespace Kyoo.Core.Controllers
return Expression.Lambda>(filter!, x);
}
- protected void SetBackingImage(T obj)
+ protected void SetBackingImage(T? obj)
{
if (obj is not IThumbnails thumbs)
return;
@@ -298,7 +298,7 @@ namespace Kyoo.Core.Controllers
/// The tracked resource with the given ID
protected virtual async Task GetWithTracking(int id)
{
- T ret = await Database.Set().AsTracking().FirstOrDefaultAsync(x => x.Id == id);
+ T? ret = await Database.Set().AsTracking().FirstOrDefaultAsync(x => x.Id == id);
SetBackingImage(ret);
if (ret == null)
throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}");
@@ -308,7 +308,7 @@ namespace Kyoo.Core.Controllers
///
public virtual async Task Get(int id)
{
- T ret = await GetOrDefault(id);
+ T? ret = await GetOrDefault(id);
if (ret == null)
throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}");
return ret;
@@ -317,7 +317,7 @@ namespace Kyoo.Core.Controllers
///
public virtual async Task Get(string slug)
{
- T ret = await GetOrDefault(slug);
+ T? ret = await GetOrDefault(slug);
if (ret == null)
throw new ItemNotFoundException($"No {typeof(T).Name} found with the slug {slug}");
return ret;
@@ -326,20 +326,20 @@ namespace Kyoo.Core.Controllers
///
public virtual async Task Get(Expression> where)
{
- T ret = await GetOrDefault(where);
+ T? ret = await GetOrDefault(where);
if (ret == null)
throw new ItemNotFoundException($"No {typeof(T).Name} found with the given predicate.");
return ret;
}
///
- public virtual Task GetOrDefault(int id)
+ public virtual Task GetOrDefault(int id)
{
return Database.Set().FirstOrDefaultAsync(x => x.Id == id).Then(SetBackingImage);
}
///
- public virtual Task GetOrDefault(string slug)
+ public virtual Task GetOrDefault(string slug)
{
if (slug == "random")
return Database.Set().OrderBy(x => EF.Functions.Random()).FirstOrDefaultAsync().Then(SetBackingImage);
@@ -347,7 +347,7 @@ namespace Kyoo.Core.Controllers
}
///
- public virtual Task GetOrDefault(Expression> where, Sort sortBy = default)
+ public virtual Task GetOrDefault(Expression> where, Sort? sortBy = default)
{
return Sort(Database.Set(), sortBy).FirstOrDefaultAsync(where).Then(SetBackingImage);
}
@@ -356,9 +356,9 @@ namespace Kyoo.Core.Controllers
public abstract Task> Search(string query);
///
- public virtual async Task> GetAll(Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ public virtual async Task> GetAll(Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
return (await ApplyFilters(Database.Set(), where, sort, limit))
.Select(SetBackingImageSelf).ToList();
@@ -373,9 +373,9 @@ namespace Kyoo.Core.Controllers
/// Pagination information (where to start and how many to get)
/// The filtered query
protected async Task> ApplyFilters(IQueryable query,
- Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
query = Sort(query, sort);
if (where != null)
@@ -395,7 +395,7 @@ namespace Kyoo.Core.Controllers
}
///
- public virtual Task GetCount(Expression> where = null)
+ public virtual Task GetCount(Expression>? where = null)
{
IQueryable query = Database.Set();
if (where != null)
@@ -411,11 +411,11 @@ namespace Kyoo.Core.Controllers
{
await _thumbs.DownloadImages(thumbs);
if (thumbs.Poster != null)
- Database.Entry(thumbs).Reference(x => x.Poster).TargetEntry.State = EntityState.Added;
+ Database.Entry(thumbs).Reference(x => x.Poster).TargetEntry!.State = EntityState.Added;
if (thumbs.Thumbnail != null)
- Database.Entry(thumbs).Reference(x => x.Thumbnail).TargetEntry.State = EntityState.Added;
+ Database.Entry(thumbs).Reference(x => x.Thumbnail).TargetEntry!.State = EntityState.Added;
if (thumbs.Logo != null)
- Database.Entry(thumbs).Reference(x => x.Logo).TargetEntry.State = EntityState.Added;
+ Database.Entry(thumbs).Reference(x => x.Logo).TargetEntry!.State = EntityState.Added;
}
SetBackingImage(obj);
return obj;
@@ -444,7 +444,7 @@ namespace Kyoo.Core.Controllers
{
try
{
- T old = await GetOrDefault(obj.Slug);
+ T? old = await GetOrDefault(obj.Slug);
if (old != null)
return old;
@@ -544,7 +544,7 @@ namespace Kyoo.Core.Controllers
{
try
{
- MethodInfo setter = typeof(T).GetProperty(nameof(resource.Slug))!.GetSetMethod();
+ MethodInfo? setter = typeof(T).GetProperty(nameof(resource.Slug))!.GetSetMethod();
if (setter != null)
setter.Invoke(resource, new object[] { resource.Slug + '!' });
else
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs
index 02d0ba84..328c3cd8 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs
@@ -126,7 +126,7 @@ namespace Kyoo.Core.Controllers
if (changed.People != null)
{
- await Database.Entry(resource).Collection(x => x.People).LoadAsync();
+ await Database.Entry(resource).Collection(x => x.People!).LoadAsync();
resource.People = changed.People;
}
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs
index 7c53b609..deee3aaf 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs
@@ -94,7 +94,7 @@ namespace Kyoo.Core.Controllers
{
foreach (PeopleRole role in resource.Roles)
{
- role.Show = _database.LocalEntity(role.Show.Slug)
+ role.Show = _database.LocalEntity(role.Show!.Slug)
?? await _shows.Value.CreateIfNotExists(role.Show);
role.ShowID = role.Show.Id;
_database.Entry(role).State = EntityState.Added;
@@ -109,7 +109,7 @@ namespace Kyoo.Core.Controllers
if (changed.Roles != null)
{
- await Database.Entry(resource).Collection(x => x.Roles).LoadAsync();
+ await Database.Entry(resource).Collection(x => x.Roles!).LoadAsync();
resource.Roles = changed.Roles;
}
}
@@ -125,9 +125,9 @@ namespace Kyoo.Core.Controllers
///
public Task> GetFromShow(int showID,
- Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
return Task.FromResult>(new List());
// ICollection people = await ApplyFilters(_database.PeopleRoles
@@ -146,9 +146,9 @@ namespace Kyoo.Core.Controllers
///
public Task> GetFromShow(string showSlug,
- Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
return Task.FromResult>(new List());
// ICollection people = await ApplyFilters(_database.PeopleRoles
@@ -169,9 +169,9 @@ namespace Kyoo.Core.Controllers
///
public Task> GetFromPeople(int id,
- Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
return Task.FromResult>(new List());
// ICollection roles = await ApplyFilters(_database.PeopleRoles
@@ -189,9 +189,9 @@ namespace Kyoo.Core.Controllers
///
public Task> GetFromPeople(string slug,
- Expression> where = null,
- Sort sort = default,
- Pagination limit = default)
+ Expression>? where = null,
+ Sort? sort = default,
+ Pagination? limit = default)
{
return Task.FromResult>(new List());
// ICollection roles = await ApplyFilters(_database.PeopleRoles
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs
index 801b4876..417539cc 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs
@@ -71,7 +71,7 @@ namespace Kyoo.Core.Controllers
///
public async Task Get(int showID, int seasonNumber)
{
- Season ret = await GetOrDefault(showID, seasonNumber);
+ Season? ret = await GetOrDefault(showID, seasonNumber);
if (ret == null)
throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showID}");
return ret;
@@ -80,23 +80,23 @@ namespace Kyoo.Core.Controllers
///
public async Task Get(string showSlug, int seasonNumber)
{
- Season ret = await GetOrDefault(showSlug, seasonNumber);
+ Season? ret = await GetOrDefault(showSlug, seasonNumber);
if (ret == null)
throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showSlug}");
return ret;
}
///
- public Task GetOrDefault(int showID, int seasonNumber)
+ public Task GetOrDefault(int showID, int seasonNumber)
{
return _database.Seasons.FirstOrDefaultAsync(x => x.ShowId == showID
&& x.SeasonNumber == seasonNumber).Then(SetBackingImage);
}
///
- public Task GetOrDefault(string showSlug, int seasonNumber)
+ public Task GetOrDefault(string showSlug, int seasonNumber)
{
- return _database.Seasons.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
+ return _database.Seasons.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug
&& x.SeasonNumber == seasonNumber).Then(SetBackingImage);
}
@@ -105,7 +105,7 @@ namespace Kyoo.Core.Controllers
{
return (await Sort(
_database.Seasons
- .Where(_database.Like(x => x.Name, $"%{query}%"))
+ .Where(_database.Like(x => x.Name!, $"%{query}%"))
)
.Take(20)
.ToListAsync())
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs
index 11887286..f52f0ce1 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs
@@ -21,6 +21,7 @@ using System.Linq;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
+using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Postgresql;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;
@@ -129,17 +130,20 @@ namespace Kyoo.Core.Controllers
if (changed.People != null)
{
- await Database.Entry(resource).Collection(x => x.People).LoadAsync();
+ await Database.Entry(resource).Collection(x => x.People!).LoadAsync();
resource.People = changed.People;
}
}
///
- public Task GetSlug(int showID)
+ public async Task GetSlug(int showID)
{
- return _database.Shows.Where(x => x.Id == showID)
+ string? ret = await _database.Shows.Where(x => x.Id == showID)
.Select(x => x.Slug)
.FirstOrDefaultAsync();
+ if (ret == null)
+ throw new ItemNotFoundException();
+ return ret;
}
///
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs
index 6e4ea323..8e40646e 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs
@@ -69,7 +69,7 @@ namespace Kyoo.Core.Controllers
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
if (obj.Logo != null)
- _database.Entry(obj).Reference(x => x.Logo).TargetEntry.State = EntityState.Added;
+ _database.Entry(obj).Reference(x => x.Logo).TargetEntry!.State = EntityState.Added;
await _database.SaveChangesAsync(() => Get(obj.Slug));
OnResourceCreated(obj);
return obj;
diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs
index ff6e9535..cd0b6d1f 100644
--- a/back/src/Kyoo.Core/CoreModule.cs
+++ b/back/src/Kyoo.Core/CoreModule.cs
@@ -84,7 +84,7 @@ namespace Kyoo.Core
options.InvalidModelStateResponseFactory = ctx =>
{
string[] errors = ctx.ModelState
- .SelectMany(x => x.Value.Errors)
+ .SelectMany(x => x.Value!.Errors)
.Select(x => x.ErrorMessage)
.ToArray();
return new BadRequestObjectResult(new RequestError(errors));
diff --git a/back/src/Kyoo.Core/Helper.cs b/back/src/Kyoo.Core/Helper.cs
deleted file mode 100644
index ad45835d..00000000
--- a/back/src/Kyoo.Core/Helper.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Kyoo - A portable and vast media library solution.
-// Copyright (c) Kyoo.
-//
-// See AUTHORS.md and LICENSE file in the project root for full license information.
-//
-// Kyoo is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// any later version.
-//
-// Kyoo is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Kyoo. If not, see .
-
-using System.Net.Http;
-using System.Threading.Tasks;
-using Newtonsoft.Json;
-
-namespace Kyoo.Core
-{
- ///
- /// A class containing helper methods.
- ///
- public static class Helper
- {
- ///
- /// An helper method to get json content from an http server. This is a temporary thing and will probably be
- /// replaced by a call to the function of the same name in the System.Net.Http.Json namespace when .net6
- /// gets released.
- ///
- /// The http server to use.
- /// The url to retrieve
- /// The type of object to convert
- /// A T representing the json contained at the given url.
- public static async Task GetFromJsonAsync(this HttpClient client, string url)
- {
- HttpResponseMessage ret = await client.GetAsync(url);
- ret.EnsureSuccessStatusCode();
- string content = await ret.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject(content);
- }
- }
-}
diff --git a/back/src/Kyoo.Core/Kyoo.Core.csproj b/back/src/Kyoo.Core/Kyoo.Core.csproj
index b4061a1c..72d5e1e6 100644
--- a/back/src/Kyoo.Core/Kyoo.Core.csproj
+++ b/back/src/Kyoo.Core/Kyoo.Core.csproj
@@ -2,6 +2,7 @@
Kyoo.Core
Kyoo.Core
+ enable
diff --git a/back/src/Kyoo.Core/Views/Helper/ApiHelper.cs b/back/src/Kyoo.Core/Views/Helper/ApiHelper.cs
index 432a7a54..0dec46a3 100644
--- a/back/src/Kyoo.Core/Views/Helper/ApiHelper.cs
+++ b/back/src/Kyoo.Core/Views/Helper/ApiHelper.cs
@@ -48,9 +48,9 @@ namespace Kyoo.Core.Api
/// The second parameter to compare.
/// A comparison expression compatible with strings
public static BinaryExpression StringCompatibleExpression(
- [NotNull] Func operand,
- [NotNull] Expression left,
- [NotNull] Expression right)
+ Func operand,
+ Expression left,
+ Expression right)
{
if (left.Type != typeof(string))
return operand(left, right);
@@ -69,14 +69,14 @@ namespace Kyoo.Core.Api
/// The type to create filters for.
/// A filter is invalid.
/// An expression representing the filters that can be used anywhere or compiled
- public static Expression> ParseWhere(Dictionary where,
- Expression> defaultWhere = null)
+ public static Expression>? ParseWhere(Dictionary? where,
+ Expression>? defaultWhere = null)
{
if (where == null || where.Count == 0)
return defaultWhere;
ParameterExpression param = defaultWhere?.Parameters.First() ?? Expression.Parameter(typeof(T));
- Expression expression = defaultWhere?.Body;
+ Expression? expression = defaultWhere?.Body;
foreach ((string key, string desired) in where)
{
@@ -91,17 +91,17 @@ namespace Kyoo.Core.Api
value = desired.Substring(desired.IndexOf(':') + 1);
}
- PropertyInfo property = typeof(T).GetProperty(key, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
+ PropertyInfo? property = typeof(T).GetProperty(key, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (property == null)
throw new ArgumentException($"No filterable parameter with the name {key}.");
MemberExpression propertyExpr = Expression.Property(param, property);
- ConstantExpression valueExpr = null;
+ ConstantExpression? valueExpr = null;
bool isList = typeof(IEnumerable).IsAssignableFrom(propertyExpr.Type) && propertyExpr.Type != typeof(string);
if (operand != "ctn" && !typeof(IResource).IsAssignableFrom(propertyExpr.Type) && !isList)
{
Type propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
- object val;
+ object? val;
try
{
val = string.IsNullOrEmpty(value) || value.Equals("null", StringComparison.OrdinalIgnoreCase)
@@ -110,7 +110,7 @@ namespace Kyoo.Core.Api
}
catch (InvalidCastException)
{
- throw new ArgumentException("Comparing two differents value's type.");
+ throw new ArgumentException("Comparing two different value's type.");
}
valueExpr = Expression.Constant(val, property.PropertyType);
@@ -166,7 +166,7 @@ namespace Kyoo.Core.Api
if (xProperty.Type == typeof(string))
{
// x.PROPRETY.Contains(value);
- return Expression.Call(xProperty, typeof(string).GetMethod("Contains", new[] { typeof(string) }), Expression.Constant(value));
+ return Expression.Call(xProperty, typeof(string).GetMethod("Contains", new[] { typeof(string) })!, Expression.Constant(value));
}
// x.PROPERTY is either a List<> or a []
@@ -176,7 +176,8 @@ namespace Kyoo.Core.Api
{
return Expression.Call(typeof(Enumerable), "Contains", new[] { inner }, xProperty, Expression.Constant(value));
}
- else if (inner.IsEnum && Enum.TryParse(inner, value, true, out object enumValue))
+
+ if (inner.IsEnum && Enum.TryParse(inner, value, true, out object? enumValue))
{
return Expression.Call(typeof(Enumerable), "Contains", new[] { inner }, xProperty, Expression.Constant(enumValue));
}
@@ -185,7 +186,7 @@ namespace Kyoo.Core.Api
throw new ArgumentException("Contain (ctn) not appliable for this property.");
// x => x.PROPERTY.Any(y => y.Slug == value)
- Expression ret = null;
+ Expression? ret = null;
ParameterExpression y = Expression.Parameter(inner, "y");
foreach (string val in value.Split(','))
{
@@ -197,7 +198,7 @@ namespace Kyoo.Core.Api
else
ret = Expression.AndAlso(ret, iteration);
}
- return ret;
+ return ret!;
}
}
}
diff --git a/back/src/Kyoo.Core/Views/Helper/CrudApi.cs b/back/src/Kyoo.Core/Views/Helper/CrudApi.cs
index a593ac9a..c89d8650 100644
--- a/back/src/Kyoo.Core/Views/Helper/CrudApi.cs
+++ b/back/src/Kyoo.Core/Views/Helper/CrudApi.cs
@@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
+using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
@@ -69,7 +70,7 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task> Get(Identifier identifier)
{
- T ret = await identifier.Match(
+ T? ret = await identifier.Match(
id => Repository.GetOrDefault(id),
slug => Repository.GetOrDefault(slug)
);
@@ -235,7 +236,11 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
public async Task Delete([FromQuery] Dictionary where)
{
- await Repository.DeleteAll(ApiHelper.ParseWhere(where));
+ Expression>? w = ApiHelper.ParseWhere(where);
+ if (w == null)
+ return BadRequest(new RequestError("Incule a filter to delete items, all items won't be deleted."));
+
+ await Repository.DeleteAll(w);
return NoContent();
}
}
diff --git a/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs b/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
index 697e75cc..a8143ebc 100644
--- a/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
+++ b/back/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
@@ -59,14 +59,14 @@ namespace Kyoo.Core.Api
private async Task _GetImage(Identifier identifier, string image, ImageQuality? quality)
{
- T resource = await identifier.Match(
+ T? resource = await identifier.Match(
id => Repository.GetOrDefault(id),
slug => Repository.GetOrDefault(slug)
);
if (resource == null)
return NotFound();
string path = _thumbs.GetImagePath(resource, image, quality ?? ImageQuality.High);
- if (path == null || !System.IO.File.Exists(path))
+ if (!System.IO.File.Exists(path))
return NotFound();
if (!identifier.Match(id => false, slug => slug == "random"))
diff --git a/back/src/Kyoo.Core/Views/Helper/ResourceViewAttribute.cs b/back/src/Kyoo.Core/Views/Helper/ResourceViewAttribute.cs
index b28dc802..c95e51af 100644
--- a/back/src/Kyoo.Core/Views/Helper/ResourceViewAttribute.cs
+++ b/back/src/Kyoo.Core/Views/Helper/ResourceViewAttribute.cs
@@ -42,7 +42,7 @@ namespace Kyoo.Core.Api
///
public override void OnActionExecuting(ActionExecutingContext context)
{
- if (context.ActionArguments.TryGetValue("where", out object dic) && dic is Dictionary where)
+ if (context.ActionArguments.TryGetValue("where", out object? dic) && dic is Dictionary where)
{
Dictionary nWhere = new(where, StringComparer.InvariantCultureIgnoreCase);
nWhere.Remove("fields");
@@ -55,7 +55,7 @@ namespace Kyoo.Core.Api
}
List fields = context.HttpContext.Request.Query["fields"]
- .SelectMany(x => x.Split(','))
+ .SelectMany(x => x!.Split(','))
.ToList();
if (context.ActionDescriptor is ControllerActionDescriptor descriptor)
@@ -77,7 +77,7 @@ namespace Kyoo.Core.Api
fields = fields
.Select(x =>
{
- string property = properties
+ string? property = properties
.FirstOrDefault(y
=> string.Equals(x, y.Name, StringComparison.InvariantCultureIgnoreCase))
?.Name;
@@ -88,6 +88,7 @@ namespace Kyoo.Core.Api
);
return null;
})
+ .OfType()
.ToList();
if (context.Result != null)
return;
@@ -111,12 +112,12 @@ namespace Kyoo.Core.Api
return;
ILibraryManager library = context.HttpContext.RequestServices.GetRequiredService();
- ICollection fields = (ICollection)context.HttpContext.Items["fields"];
- Type pageType = Utility.GetGenericDefinition(result.DeclaredType, typeof(Page<>));
+ ICollection fields = (ICollection)context.HttpContext.Items["fields"]!;
+ Type? pageType = Utility.GetGenericDefinition(result.DeclaredType, typeof(Page<>));
if (pageType != null)
{
- foreach (IResource resource in ((dynamic)result.Value).Items)
+ foreach (IResource resource in ((dynamic)result.Value!).Items)
{
foreach (string field in fields!)
await library.Load(resource, field);
@@ -125,7 +126,7 @@ namespace Kyoo.Core.Api
else if (result.DeclaredType.IsAssignableTo(typeof(IResource)))
{
foreach (string field in fields!)
- await library.Load((IResource)result.Value, field);
+ await library.Load((IResource)result.Value!, field);
}
}
}
diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs
index a5daeec4..bda5db67 100644
--- a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs
+++ b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs
@@ -53,16 +53,16 @@ namespace Kyoo.Core.Api
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
- LoadableRelationAttribute relation = member.GetCustomAttribute();
+ LoadableRelationAttribute? relation = member.GetCustomAttribute();
if (relation != null)
{
property.ShouldSerialize = _ =>
{
- string resType = (string)_httpContextAccessor.HttpContext!.Items["ResourceType"];
+ string resType = (string)_httpContextAccessor.HttpContext!.Items["ResourceType"]!;
if (member.DeclaringType!.Name != resType)
return false;
- ICollection fields = (ICollection)_httpContextAccessor.HttpContext!.Items["fields"];
- return fields!.Contains(member.Name);
+ ICollection fields = (ICollection)_httpContextAccessor.HttpContext!.Items["fields"]!;
+ return fields.Contains(member.Name);
};
}
diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/PeopleRoleConverter.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/PeopleRoleConverter.cs
index f4db9075..3aa4304b 100644
--- a/back/src/Kyoo.Core/Views/Helper/Serializers/PeopleRoleConverter.cs
+++ b/back/src/Kyoo.Core/Views/Helper/Serializers/PeopleRoleConverter.cs
@@ -31,10 +31,16 @@ namespace Kyoo.Core.Api
public class PeopleRoleConverter : JsonConverter
{
///
- public override void WriteJson(JsonWriter writer, PeopleRole value, JsonSerializer serializer)
+ public override void WriteJson(JsonWriter writer, PeopleRole? value, JsonSerializer serializer)
{
- ICollection oldPeople = value.Show?.People;
- ICollection oldRoles = value.People?.Roles;
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ ICollection? oldPeople = value.Show?.People;
+ ICollection? oldRoles = value.People?.Roles;
if (value.Show != null)
value.Show.People = null;
if (value.People != null)
@@ -54,7 +60,7 @@ namespace Kyoo.Core.Api
///
public override PeopleRole ReadJson(JsonReader reader,
Type objectType,
- PeopleRole existingValue,
+ PeopleRole? existingValue,
bool hasExistingValue,
JsonSerializer serializer)
{
diff --git a/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs b/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs
index afcfe3b0..7918cf4f 100644
--- a/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs
+++ b/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs
@@ -85,7 +85,7 @@ namespace Kyoo.Core.Api
[FromQuery] Dictionary where,
[FromQuery] Pagination pagination)
{
- Expression> whereQuery = ApiHelper.ParseWhere(where);
+ Expression>? whereQuery = ApiHelper.ParseWhere(where);
Sort sort = Sort.From(sortBy);
ICollection