New Scanner + People Pages (#3286)

Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
Joe Milazzo 2024-10-23 15:11:18 -07:00 committed by GitHub
parent 1ed0eae22d
commit ba20ad4ecc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
142 changed files with 17529 additions and 3038 deletions

View file

@ -4,6 +4,7 @@ using API.Data.Misc;
using API.Data.Repositories;
using API.Entities;
using API.Entities.Metadata;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
namespace API.Extensions.QueryExtensions.Filtering;
@ -45,10 +46,25 @@ public static class SearchQueryableExtensions
public static IQueryable<Person> SearchPeople(this IQueryable<SeriesMetadata> queryable,
string searchQuery, IEnumerable<int> seriesIds)
{
return queryable
// Get people from SeriesMetadata
var peopleFromSeriesMetadata = queryable
.Where(sm => seriesIds.Contains(sm.SeriesId))
.SelectMany(sm => sm.People.Where(t => t.Name != null && EF.Functions.Like(t.Name, $"%{searchQuery}%")))
.AsSplitQuery()
.SelectMany(sm => sm.People)
.Where(p => p.Person.Name != null && EF.Functions.Like(p.Person.Name, $"%{searchQuery}%"))
.Select(p => p.Person);
// Get people from ChapterPeople by navigating through Volume -> Series
var peopleFromChapterPeople = queryable
.Where(sm => seriesIds.Contains(sm.SeriesId))
.SelectMany(sm => sm.Series.Volumes)
.SelectMany(v => v.Chapters)
.SelectMany(ch => ch.People)
.Where(cp => cp.Person.Name != null && EF.Functions.Like(cp.Person.Name, $"%{searchQuery}%"))
.Select(cp => cp.Person);
// Combine both queries and ensure distinct results
return peopleFromSeriesMetadata
.Union(peopleFromChapterPeople)
.Distinct()
.OrderBy(p => p.NormalizedName);
}

View file

@ -471,22 +471,22 @@ public static class SeriesFilter
{
case FilterComparison.Equal:
case FilterComparison.Contains:
return queryable.Where(s => s.Metadata.People.Any(p => people.Contains(p.Id)));
return queryable.Where(s => s.Metadata.People.Any(p => people.Contains(p.PersonId)));
case FilterComparison.NotEqual:
case FilterComparison.NotContains:
return queryable.Where(s => s.Metadata.People.All(t => !people.Contains(t.Id)));
return queryable.Where(s => s.Metadata.People.All(t => !people.Contains(t.PersonId)));
case FilterComparison.MustContains:
// Deconstruct and do a Union of a bunch of where statements since this doesn't translate
var queries = new List<IQueryable<Series>>()
{
queryable
};
queries.AddRange(people.Select(gId => queryable.Where(s => s.Metadata.People.Any(p => p.Id == gId))));
queries.AddRange(people.Select(gId => queryable.Where(s => s.Metadata.People.Any(p => p.PersonId == gId))));
return queries.Aggregate((q1, q2) => q1.Intersect(q2));
case FilterComparison.IsEmpty:
// Check if there are no people with specific roles (e.g., Writer, Penciller, etc.)
return queryable.Where(s => !s.Metadata.People.Any(p => p.Role == role));
return queryable.Where(s => s.Metadata.People.All(p => p.Role != role));
case FilterComparison.GreaterThan:
case FilterComparison.GreaterThanEqual:
case FilterComparison.LessThan:
@ -513,17 +513,17 @@ public static class SeriesFilter
{
case FilterComparison.Equal:
case FilterComparison.Contains:
return queryable.Where(s => s.Metadata.People.Any(p => people.Contains(p.Id)));
return queryable.Where(s => s.Metadata.People.Any(p => people.Contains(p.PersonId)));
case FilterComparison.NotEqual:
case FilterComparison.NotContains:
return queryable.Where(s => s.Metadata.People.All(t => !people.Contains(t.Id)));
return queryable.Where(s => s.Metadata.People.All(t => !people.Contains(t.PersonId)));
case FilterComparison.MustContains:
// Deconstruct and do a Union of a bunch of where statements since this doesn't translate
var queries = new List<IQueryable<Series>>()
{
queryable
};
queries.AddRange(people.Select(gId => queryable.Where(s => s.Metadata.People.Any(p => p.Id == gId))));
queries.AddRange(people.Select(gId => queryable.Where(s => s.Metadata.People.Any(p => p.PersonId == gId))));
return queries.Aggregate((q1, q2) => q1.Intersect(q2));
case FilterComparison.IsEmpty:

View file

@ -56,7 +56,8 @@ public static class IncludesExtensions
if (includes.HasFlag(ChapterIncludes.People))
{
queryable = queryable
.Include(c => c.People);
.Include(c => c.People)
.ThenInclude(cp => cp.Person);
}
if (includes.HasFlag(ChapterIncludes.Genres))
@ -161,17 +162,16 @@ public static class IncludesExtensions
if (includeFlags.HasFlag(SeriesIncludes.Metadata))
{
query = query.Include(s => s.Metadata)
.ThenInclude(m => m.CollectionTags.OrderBy(g => g.NormalizedTitle))
query = query
.Include(s => s.Metadata)
.ThenInclude(m => m.Genres.OrderBy(g => g.NormalizedTitle))
.Include(s => s.Metadata)
.ThenInclude(m => m.People)
.ThenInclude(smp => smp.Person)
.Include(s => s.Metadata)
.ThenInclude(m => m.Tags.OrderBy(g => g.NormalizedTitle));
}
return query.AsSplitQuery();
}

View file

@ -25,6 +25,19 @@ public static class RestrictByAgeExtensions
return q;
}
public static IQueryable<Chapter> RestrictAgainstAgeRestriction(this IQueryable<Chapter> queryable, AgeRestriction restriction)
{
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
var q = queryable.Where(chapter => chapter.Volume.Series.Metadata.AgeRating <= restriction.AgeRating);
if (!restriction.IncludeUnknowns)
{
return q.Where(s => s.Volume.Series.Metadata.AgeRating != AgeRating.Unknown);
}
return q;
}
[Obsolete]
public static IQueryable<CollectionTag> RestrictAgainstAgeRestriction(this IQueryable<CollectionTag> queryable, AgeRestriction restriction)
{
@ -88,12 +101,12 @@ public static class RestrictByAgeExtensions
if (restriction.IncludeUnknowns)
{
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
sm.AgeRating <= restriction.AgeRating));
return queryable.Where(c => c.SeriesMetadataPeople.All(sm =>
sm.SeriesMetadata.AgeRating <= restriction.AgeRating));
}
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
return queryable.Where(c => c.SeriesMetadataPeople.All(sm =>
sm.SeriesMetadata.AgeRating <= restriction.AgeRating && sm.SeriesMetadata.AgeRating > AgeRating.Unknown));
}
public static IQueryable<ReadingList> RestrictAgainstAgeRestriction(this IQueryable<ReadingList> queryable, AgeRestriction restriction)