Collection Rework (#2830)

This commit is contained in:
Joe Milazzo 2024-04-06 12:03:49 -05:00 committed by GitHub
parent 0dacc061f1
commit deaaccb96a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
93 changed files with 5413 additions and 1120 deletions

View file

@ -0,0 +1,76 @@
using System.Collections.Generic;
using System.Linq;
using API.Data.Misc;
using API.Data.Repositories;
using API.Entities;
using API.Entities.Metadata;
using Microsoft.EntityFrameworkCore;
namespace API.Extensions.QueryExtensions.Filtering;
public static class SearchQueryableExtensions
{
public static IQueryable<AppUserCollection> Search(this IQueryable<AppUserCollection> queryable,
string searchQuery, int userId, AgeRestriction userRating)
{
return queryable
.Where(uc => uc.Promoted || uc.AppUserId == userId)
.Where(s => EF.Functions.Like(s.Title!, $"%{searchQuery}%")
|| EF.Functions.Like(s.NormalizedTitle!, $"%{searchQuery}%"))
.RestrictAgainstAgeRestriction(userRating)
.OrderBy(s => s.NormalizedTitle);
}
public static IQueryable<ReadingList> Search(this IQueryable<ReadingList> queryable,
string searchQuery, int userId, AgeRestriction userRating)
{
return queryable
.Where(rl => rl.AppUserId == userId || rl.Promoted)
.Where(rl => EF.Functions.Like(rl.Title, $"%{searchQuery}%"))
.RestrictAgainstAgeRestriction(userRating)
.OrderBy(s => s.NormalizedTitle);
}
public static IQueryable<Library> Search(this IQueryable<Library> queryable,
string searchQuery, int userId, IEnumerable<int> libraryIds)
{
return queryable
.Where(l => libraryIds.Contains(l.Id))
.Where(l => EF.Functions.Like(l.Name, $"%{searchQuery}%"))
.IsRestricted(QueryContext.Search)
.AsSplitQuery()
.OrderBy(l => l.Name.ToLower());
}
public static IQueryable<Person> SearchPeople(this IQueryable<SeriesMetadata> queryable,
string searchQuery, IEnumerable<int> seriesIds)
{
return queryable
.Where(sm => seriesIds.Contains(sm.SeriesId))
.SelectMany(sm => sm.People.Where(t => t.Name != null && EF.Functions.Like(t.Name, $"%{searchQuery}%")))
.AsSplitQuery()
.Distinct()
.OrderBy(p => p.NormalizedName);
}
public static IQueryable<Genre> SearchGenres(this IQueryable<SeriesMetadata> queryable,
string searchQuery, IEnumerable<int> seriesIds)
{
return queryable
.Where(sm => seriesIds.Contains(sm.SeriesId))
.SelectMany(sm => sm.Genres.Where(t => EF.Functions.Like(t.Title, $"%{searchQuery}%")))
.Distinct()
.OrderBy(t => t.NormalizedTitle);
}
public static IQueryable<Tag> SearchTags(this IQueryable<SeriesMetadata> queryable,
string searchQuery, IEnumerable<int> seriesIds)
{
return queryable
.Where(sm => seriesIds.Contains(sm.SeriesId))
.SelectMany(sm => sm.Tags.Where(t => EF.Functions.Like(t.Title, $"%{searchQuery}%")))
.AsSplitQuery()
.Distinct()
.OrderBy(t => t.NormalizedTitle);
}
}

View file

@ -551,25 +551,26 @@ public static class SeriesFilter
}
public static IQueryable<Series> HasCollectionTags(this IQueryable<Series> queryable, bool condition,
FilterComparison comparison, IList<int> collectionTags)
FilterComparison comparison, IList<int> collectionTags, IList<int> collectionSeries)
{
if (!condition || collectionTags.Count == 0) return queryable;
switch (comparison)
{
case FilterComparison.Equal:
case FilterComparison.Contains:
return queryable.Where(s => s.Metadata.CollectionTags.Any(t => collectionTags.Contains(t.Id)));
return queryable.Where(s => collectionSeries.Contains(s.Id));
case FilterComparison.NotContains:
case FilterComparison.NotEqual:
return queryable.Where(s => !s.Metadata.CollectionTags.Any(t => collectionTags.Contains(t.Id)));
return queryable.Where(s => !collectionSeries.Contains(s.Id));
case FilterComparison.MustContains:
// Deconstruct and do a Union of a bunch of where statements since this doesn't translate
// // 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(collectionTags.Select(gId => queryable.Where(s => s.Metadata.CollectionTags.Any(p => p.Id == gId))));
queries.AddRange(collectionSeries.Select(gId => queryable.Where(s => collectionSeries.Any(p => p == s.Id))));
return queries.Aggregate((q1, q2) => q1.Intersect(q2));
case FilterComparison.GreaterThan:

View file

@ -19,6 +19,23 @@ public static class IncludesExtensions
queryable = queryable.Include(c => c.SeriesMetadatas);
}
if (includes.HasFlag(CollectionTagIncludes.SeriesMetadataWithSeries))
{
queryable = queryable.Include(c => c.SeriesMetadatas).ThenInclude(s => s.Series);
}
return queryable.AsSplitQuery();
}
public static IQueryable<AppUserCollection> Includes(this IQueryable<AppUserCollection> queryable,
CollectionIncludes includes)
{
if (includes.HasFlag(CollectionIncludes.Series))
{
queryable = queryable.Include(c => c.Items);
}
return queryable.AsSplitQuery();
}
@ -206,6 +223,12 @@ public static class IncludesExtensions
query = query.Include(u => u.ExternalSources);
}
if (includeFlags.HasFlag(AppUserIncludes.Collections))
{
query = query.Include(u => u.Collections)
.ThenInclude(c => c.Items);
}
return query.AsSplitQuery();
}

View file

@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using API.Data.Misc;
using API.Entities;
using API.Entities.Enums;
@ -24,6 +25,7 @@ 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;
@ -38,6 +40,20 @@ public static class RestrictByAgeExtensions
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
}
public static IQueryable<AppUserCollection> RestrictAgainstAgeRestriction(this IQueryable<AppUserCollection> queryable, AgeRestriction restriction)
{
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
if (restriction.IncludeUnknowns)
{
return queryable.Where(c => c.Items.All(sm =>
sm.Metadata.AgeRating <= restriction.AgeRating));
}
return queryable.Where(c => c.Items.All(sm =>
sm.Metadata.AgeRating <= restriction.AgeRating && sm.Metadata.AgeRating > AgeRating.Unknown));
}
public static IQueryable<Genre> RestrictAgainstAgeRestriction(this IQueryable<Genre> queryable, AgeRestriction restriction)
{
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;