Browse by Genre/Tag/Person with new metadata system for People (#3835)
Co-authored-by: Stepan Goremykin <s.goremykin@proton.me> Co-authored-by: goremykin <goremukin@gmail.com> Co-authored-by: Christopher <39032787+MrRobotjs@users.noreply.github.com> Co-authored-by: Fesaa <77553571+Fesaa@users.noreply.github.com>
This commit is contained in:
parent
00c4712fc3
commit
c52ed1f65d
147 changed files with 6612 additions and 958 deletions
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using System.Text.RegularExpressions;
|
||||
using API.Data.Misc;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
|
||||
namespace API.Extensions;
|
||||
#nullable enable
|
||||
|
@ -42,4 +43,16 @@ public static class EnumerableExtensions
|
|||
|
||||
return q;
|
||||
}
|
||||
|
||||
public static IEnumerable<SeriesMetadata> RestrictAgainstAgeRestriction(this IEnumerable<SeriesMetadata> items, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return items;
|
||||
var q = items.Where(s => s.AgeRating <= restriction.AgeRating);
|
||||
if (!restriction.IncludeUnknowns)
|
||||
{
|
||||
return q.Where(s => s.AgeRating != AgeRating.Unknown);
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
|
136
API/Extensions/QueryExtensions/Filtering/PersonFilter.cs
Normal file
136
API/Extensions/QueryExtensions/Filtering/PersonFilter.cs
Normal file
|
@ -0,0 +1,136 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using API.DTOs.Filtering.v2;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Person;
|
||||
using Kavita.Common;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Extensions.QueryExtensions.Filtering;
|
||||
|
||||
public static class PersonFilter
|
||||
{
|
||||
public static IQueryable<Person> HasPersonName(this IQueryable<Person> queryable, bool condition,
|
||||
FilterComparison comparison, string queryString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(queryString) || !condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Equal => queryable.Where(p => p.Name.Equals(queryString)),
|
||||
FilterComparison.BeginsWith => queryable.Where(p => EF.Functions.Like(p.Name, $"{queryString}%")),
|
||||
FilterComparison.EndsWith => queryable.Where(p => EF.Functions.Like(p.Name, $"%{queryString}")),
|
||||
FilterComparison.Matches => queryable.Where(p => EF.Functions.Like(p.Name, $"%{queryString}%")),
|
||||
FilterComparison.NotEqual => queryable.Where(p => p.Name != queryString),
|
||||
FilterComparison.NotContains or FilterComparison.GreaterThan or FilterComparison.GreaterThanEqual
|
||||
or FilterComparison.LessThan or FilterComparison.LessThanEqual or FilterComparison.Contains
|
||||
or FilterComparison.IsBefore or FilterComparison.IsAfter or FilterComparison.IsInLast
|
||||
or FilterComparison.IsNotInLast or FilterComparison.MustContains
|
||||
or FilterComparison.IsEmpty =>
|
||||
throw new KavitaException($"{comparison} not applicable for Person.Name"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison,
|
||||
"Filter Comparison is not supported")
|
||||
};
|
||||
}
|
||||
public static IQueryable<Person> HasPersonRole(this IQueryable<Person> queryable, bool condition,
|
||||
FilterComparison comparison, IList<PersonRole> roles)
|
||||
{
|
||||
if (roles == null || roles.Count == 0 || !condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Contains or FilterComparison.MustContains => queryable.Where(p =>
|
||||
p.SeriesMetadataPeople.Any(smp => roles.Contains(smp.Role)) ||
|
||||
p.ChapterPeople.Any(cmp => roles.Contains(cmp.Role))),
|
||||
FilterComparison.NotContains => queryable.Where(p =>
|
||||
!p.SeriesMetadataPeople.Any(smp => roles.Contains(smp.Role)) &&
|
||||
!p.ChapterPeople.Any(cmp => roles.Contains(cmp.Role))),
|
||||
FilterComparison.Equal or FilterComparison.NotEqual or FilterComparison.BeginsWith
|
||||
or FilterComparison.EndsWith or FilterComparison.Matches or FilterComparison.GreaterThan
|
||||
or FilterComparison.GreaterThanEqual or FilterComparison.LessThan or FilterComparison.LessThanEqual
|
||||
or FilterComparison.IsBefore or FilterComparison.IsAfter or FilterComparison.IsInLast
|
||||
or FilterComparison.IsNotInLast
|
||||
or FilterComparison.IsEmpty =>
|
||||
throw new KavitaException($"{comparison} not applicable for Person.Role"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison,
|
||||
"Filter Comparison is not supported")
|
||||
};
|
||||
}
|
||||
|
||||
public static IQueryable<Person> HasPersonSeriesCount(this IQueryable<Person> queryable, bool condition,
|
||||
FilterComparison comparison, int count)
|
||||
{
|
||||
if (!condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Equal => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() == count),
|
||||
FilterComparison.GreaterThan => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() > count),
|
||||
FilterComparison.GreaterThanEqual => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() >= count),
|
||||
FilterComparison.LessThan => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() < count),
|
||||
FilterComparison.LessThanEqual => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() <= count),
|
||||
FilterComparison.NotEqual => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() != count),
|
||||
FilterComparison.BeginsWith or FilterComparison.EndsWith or FilterComparison.Matches
|
||||
or FilterComparison.Contains or FilterComparison.NotContains or FilterComparison.IsBefore
|
||||
or FilterComparison.IsAfter or FilterComparison.IsInLast or FilterComparison.IsNotInLast
|
||||
or FilterComparison.MustContains
|
||||
or FilterComparison.IsEmpty => throw new KavitaException(
|
||||
$"{comparison} not applicable for Person.SeriesCount"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison, "Filter Comparison is not supported")
|
||||
};
|
||||
}
|
||||
|
||||
public static IQueryable<Person> HasPersonChapterCount(this IQueryable<Person> queryable, bool condition,
|
||||
FilterComparison comparison, int count)
|
||||
{
|
||||
if (!condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Equal => queryable.Where(p =>
|
||||
p.ChapterPeople.Select(cp => cp.Chapter.Id).Distinct().Count() == count),
|
||||
FilterComparison.GreaterThan => queryable.Where(p => p.ChapterPeople
|
||||
.Select(cp => cp.Chapter.Id)
|
||||
.Distinct()
|
||||
.Count() > count),
|
||||
FilterComparison.GreaterThanEqual => queryable.Where(p => p.ChapterPeople
|
||||
.Select(cp => cp.Chapter.Id)
|
||||
.Distinct()
|
||||
.Count() >= count),
|
||||
FilterComparison.LessThan => queryable.Where(p =>
|
||||
p.ChapterPeople.Select(cp => cp.Chapter.Id).Distinct().Count() < count),
|
||||
FilterComparison.LessThanEqual => queryable.Where(p => p.ChapterPeople
|
||||
.Select(cp => cp.Chapter.Id)
|
||||
.Distinct()
|
||||
.Count() <= count),
|
||||
FilterComparison.NotEqual => queryable.Where(p =>
|
||||
p.ChapterPeople.Select(cp => cp.Chapter.Id).Distinct().Count() != count),
|
||||
FilterComparison.BeginsWith or FilterComparison.EndsWith or FilterComparison.Matches
|
||||
or FilterComparison.Contains or FilterComparison.NotContains or FilterComparison.IsBefore
|
||||
or FilterComparison.IsAfter or FilterComparison.IsInLast or FilterComparison.IsNotInLast
|
||||
or FilterComparison.MustContains
|
||||
or FilterComparison.IsEmpty => throw new KavitaException(
|
||||
$"{comparison} not applicable for Person.ChapterCount"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison, "Filter Comparison is not supported")
|
||||
};
|
||||
}
|
||||
}
|
|
@ -5,10 +5,13 @@ using System.Linq.Expressions;
|
|||
using System.Threading.Tasks;
|
||||
using API.Data.Misc;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs;
|
||||
using API.DTOs.Filtering;
|
||||
using API.DTOs.KavitaPlus.Manage;
|
||||
using API.DTOs.Metadata.Browse;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Person;
|
||||
using API.Entities.Scrobble;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
@ -273,6 +276,27 @@ public static class QueryableExtensions
|
|||
};
|
||||
}
|
||||
|
||||
public static IQueryable<Person> SortBy(this IQueryable<Person> query, PersonSortOptions? sort)
|
||||
{
|
||||
if (sort == null)
|
||||
{
|
||||
return query.OrderBy(p => p.Name);
|
||||
}
|
||||
|
||||
return sort.SortField switch
|
||||
{
|
||||
PersonSortField.Name when sort.IsAscending => query.OrderBy(p => p.Name),
|
||||
PersonSortField.Name => query.OrderByDescending(p => p.Name),
|
||||
PersonSortField.SeriesCount when sort.IsAscending => query.OrderBy(p => p.SeriesMetadataPeople.Count),
|
||||
PersonSortField.SeriesCount => query.OrderByDescending(p => p.SeriesMetadataPeople.Count),
|
||||
PersonSortField.ChapterCount when sort.IsAscending => query.OrderBy(p => p.ChapterPeople.Count),
|
||||
PersonSortField.ChapterCount => query.OrderByDescending(p => p.ChapterPeople.Count),
|
||||
_ => query.OrderBy(p => p.Name)
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs either OrderBy or OrderByDescending on the given query based on the value of SortOptions.IsAscending.
|
||||
/// </summary>
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||
using API.Data.Misc;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Entities.Person;
|
||||
|
||||
namespace API.Extensions.QueryExtensions;
|
||||
|
@ -26,6 +27,7 @@ public static class RestrictByAgeExtensions
|
|||
return q;
|
||||
}
|
||||
|
||||
|
||||
public static IQueryable<Chapter> RestrictAgainstAgeRestriction(this IQueryable<Chapter> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
@ -39,20 +41,6 @@ public static class RestrictByAgeExtensions
|
|||
return q;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static IQueryable<CollectionTag> RestrictAgainstAgeRestriction(this IQueryable<CollectionTag> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
public static IQueryable<AppUserCollection> RestrictAgainstAgeRestriction(this IQueryable<AppUserCollection> queryable, AgeRestriction restriction)
|
||||
{
|
||||
|
@ -74,12 +62,15 @@ public static class RestrictByAgeExtensions
|
|||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
return queryable.Where(c =>
|
||||
c.SeriesMetadatas.Any(sm => sm.AgeRating <= restriction.AgeRating) ||
|
||||
c.Chapters.Any(cp => cp.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
return queryable.Where(c =>
|
||||
c.SeriesMetadatas.Any(sm => sm.AgeRating <= restriction.AgeRating && sm.AgeRating != AgeRating.Unknown) ||
|
||||
c.Chapters.Any(cp => cp.AgeRating <= restriction.AgeRating && cp.AgeRating != AgeRating.Unknown)
|
||||
);
|
||||
}
|
||||
|
||||
public static IQueryable<Tag> RestrictAgainstAgeRestriction(this IQueryable<Tag> queryable, AgeRestriction restriction)
|
||||
|
@ -88,12 +79,15 @@ public static class RestrictByAgeExtensions
|
|||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
return queryable.Where(c =>
|
||||
c.SeriesMetadatas.Any(sm => sm.AgeRating <= restriction.AgeRating) ||
|
||||
c.Chapters.Any(cp => cp.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
return queryable.Where(c =>
|
||||
c.SeriesMetadatas.Any(sm => sm.AgeRating <= restriction.AgeRating && sm.AgeRating != AgeRating.Unknown) ||
|
||||
c.Chapters.Any(cp => cp.AgeRating <= restriction.AgeRating && cp.AgeRating != AgeRating.Unknown)
|
||||
);
|
||||
}
|
||||
|
||||
public static IQueryable<Person> RestrictAgainstAgeRestriction(this IQueryable<Person> queryable, AgeRestriction restriction)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue