Smart Filter Polish & New Filters (#2283)
This commit is contained in:
parent
0d8c081093
commit
45f6fb67d4
23 changed files with 375 additions and 181 deletions
|
|
@ -40,6 +40,10 @@ public enum FilterField
|
|||
/// <summary>
|
||||
/// On Want To Read or Not
|
||||
/// </summary>
|
||||
WantToRead = 26
|
||||
WantToRead = 26,
|
||||
/// <summary>
|
||||
/// Last time User Read
|
||||
/// </summary>
|
||||
ReadingDate = 27
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -868,8 +868,6 @@ public class SeriesRepository : ISeriesRepository
|
|||
.HasGenre(hasGenresFilter, FilterComparison.Contains, filter.Genres)
|
||||
.HasFormat(filter.Formats != null && filter.Formats.Count > 0, FilterComparison.Contains, filter.Formats!)
|
||||
.HasAverageReadTime(true, FilterComparison.GreaterThanEqual, 0)
|
||||
|
||||
// TODO: This needs different treatment
|
||||
.HasPeople(hasPeopleFilter, FilterComparison.Contains, allPeopleIds)
|
||||
|
||||
.WhereIf(onlyParentSeries,
|
||||
|
|
@ -917,6 +915,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
SortField.LastChapterAdded => query.OrderBy(s => s.LastChapterAdded),
|
||||
SortField.TimeToRead => query.OrderBy(s => s.AvgHoursToRead),
|
||||
SortField.ReleaseYear => query.OrderBy(s => s.Metadata.ReleaseYear),
|
||||
SortField.ReadProgress => query.OrderBy(s => s.Progress.Where(p => p.SeriesId == s.Id).Select(p => p.LastModified).Max()),
|
||||
_ => query
|
||||
};
|
||||
}
|
||||
|
|
@ -930,6 +929,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
SortField.LastChapterAdded => query.OrderByDescending(s => s.LastChapterAdded),
|
||||
SortField.TimeToRead => query.OrderByDescending(s => s.AvgHoursToRead),
|
||||
SortField.ReleaseYear => query.OrderByDescending(s => s.Metadata.ReleaseYear),
|
||||
SortField.ReadProgress => query.OrderByDescending(s => s.Progress.Where(p => p.SeriesId == s.Id).Select(p => p.LastModified).Max()),
|
||||
_ => query
|
||||
};
|
||||
}
|
||||
|
|
@ -1089,6 +1089,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
FilterField.Formats => query.HasFormat(true, statement.Comparison, (IList<MangaFormat>) value),
|
||||
FilterField.ReleaseYear => query.HasReleaseYear(true, statement.Comparison, (int) value),
|
||||
FilterField.ReadTime => query.HasAverageReadTime(true, statement.Comparison, (int) value),
|
||||
FilterField.ReadingDate => query.HasReadingDate(true, statement.Comparison, (DateTime) value, userId),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -439,8 +439,8 @@ public class UserRepository : IUserRepository
|
|||
var filterSeriesQuery = query.Join(_context.Series, b => b.SeriesId, s => s.Id,
|
||||
(bookmark, series) => new BookmarkSeriesPair()
|
||||
{
|
||||
bookmark = bookmark,
|
||||
series = series
|
||||
Bookmark = bookmark,
|
||||
Series = series
|
||||
});
|
||||
|
||||
var filterStatement = filter.Statements.FirstOrDefault(f => f.Field == FilterField.SeriesName);
|
||||
|
|
@ -457,34 +457,34 @@ public class UserRepository : IUserRepository
|
|||
switch (filterStatement.Comparison)
|
||||
{
|
||||
case FilterComparison.Equal:
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => s.series.Name.Equals(queryString)
|
||||
|| s.series.OriginalName.Equals(queryString)
|
||||
|| s.series.LocalizedName.Equals(queryString)
|
||||
|| s.series.SortName.Equals(queryString));
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => s.Series.Name.Equals(queryString)
|
||||
|| s.Series.OriginalName.Equals(queryString)
|
||||
|| s.Series.LocalizedName.Equals(queryString)
|
||||
|| s.Series.SortName.Equals(queryString));
|
||||
break;
|
||||
case FilterComparison.BeginsWith:
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => EF.Functions.Like(s.series.Name, $"{queryString}%")
|
||||
||EF.Functions.Like(s.series.OriginalName, $"{queryString}%")
|
||||
|| EF.Functions.Like(s.series.LocalizedName, $"{queryString}%")
|
||||
|| EF.Functions.Like(s.series.SortName, $"{queryString}%"));
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => EF.Functions.Like(s.Series.Name, $"{queryString}%")
|
||||
||EF.Functions.Like(s.Series.OriginalName, $"{queryString}%")
|
||||
|| EF.Functions.Like(s.Series.LocalizedName, $"{queryString}%")
|
||||
|| EF.Functions.Like(s.Series.SortName, $"{queryString}%"));
|
||||
break;
|
||||
case FilterComparison.EndsWith:
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => EF.Functions.Like(s.series.Name, $"%{queryString}")
|
||||
||EF.Functions.Like(s.series.OriginalName, $"%{queryString}")
|
||||
|| EF.Functions.Like(s.series.LocalizedName, $"%{queryString}")
|
||||
|| EF.Functions.Like(s.series.SortName, $"%{queryString}"));
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => EF.Functions.Like(s.Series.Name, $"%{queryString}")
|
||||
||EF.Functions.Like(s.Series.OriginalName, $"%{queryString}")
|
||||
|| EF.Functions.Like(s.Series.LocalizedName, $"%{queryString}")
|
||||
|| EF.Functions.Like(s.Series.SortName, $"%{queryString}"));
|
||||
break;
|
||||
case FilterComparison.Matches:
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => EF.Functions.Like(s.series.Name, $"%{queryString}%")
|
||||
||EF.Functions.Like(s.series.OriginalName, $"%{queryString}%")
|
||||
|| EF.Functions.Like(s.series.LocalizedName, $"%{queryString}%")
|
||||
|| EF.Functions.Like(s.series.SortName, $"%{queryString}%"));
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => EF.Functions.Like(s.Series.Name, $"%{queryString}%")
|
||||
||EF.Functions.Like(s.Series.OriginalName, $"%{queryString}%")
|
||||
|| EF.Functions.Like(s.Series.LocalizedName, $"%{queryString}%")
|
||||
|| EF.Functions.Like(s.Series.SortName, $"%{queryString}%"));
|
||||
break;
|
||||
case FilterComparison.NotEqual:
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => s.series.Name != queryString
|
||||
|| s.series.OriginalName != queryString
|
||||
|| s.series.LocalizedName != queryString
|
||||
|| s.series.SortName != queryString);
|
||||
filterSeriesQuery = filterSeriesQuery.Where(s => s.Series.Name != queryString
|
||||
|| s.Series.OriginalName != queryString
|
||||
|| s.Series.LocalizedName != queryString
|
||||
|| s.Series.SortName != queryString);
|
||||
break;
|
||||
case FilterComparison.MustContains:
|
||||
case FilterComparison.NotContains:
|
||||
|
|
@ -504,7 +504,7 @@ public class UserRepository : IUserRepository
|
|||
return await ApplyLimit(filterSeriesQuery
|
||||
.Sort(filter.SortOptions)
|
||||
.AsSplitQuery(), filter.LimitTo)
|
||||
.Select(o => o.bookmark)
|
||||
.Select(o => o.Bookmark)
|
||||
.ProjectTo<BookmarkDto>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ namespace API.Extensions.QueryExtensions.Filtering;
|
|||
|
||||
public class BookmarkSeriesPair
|
||||
{
|
||||
public AppUserBookmark bookmark { get; set; }
|
||||
public Series series { get; set; }
|
||||
public AppUserBookmark Bookmark { get; set; }
|
||||
public Series Series { get; set; }
|
||||
}
|
||||
|
||||
public static class BookmarkSort
|
||||
|
|
@ -31,12 +31,13 @@ public static class BookmarkSort
|
|||
{
|
||||
query = sortOptions.SortField switch
|
||||
{
|
||||
SortField.SortName => query.OrderBy(s => s.series.SortName.ToLower()),
|
||||
SortField.CreatedDate => query.OrderBy(s => s.series.Created),
|
||||
SortField.LastModifiedDate => query.OrderBy(s => s.series.LastModified),
|
||||
SortField.LastChapterAdded => query.OrderBy(s => s.series.LastChapterAdded),
|
||||
SortField.TimeToRead => query.OrderBy(s => s.series.AvgHoursToRead),
|
||||
SortField.ReleaseYear => query.OrderBy(s => s.series.Metadata.ReleaseYear),
|
||||
SortField.SortName => query.OrderBy(s => s.Series.SortName.ToLower()),
|
||||
SortField.CreatedDate => query.OrderBy(s => s.Series.Created),
|
||||
SortField.LastModifiedDate => query.OrderBy(s => s.Series.LastModified),
|
||||
SortField.LastChapterAdded => query.OrderBy(s => s.Series.LastChapterAdded),
|
||||
SortField.TimeToRead => query.OrderBy(s => s.Series.AvgHoursToRead),
|
||||
SortField.ReleaseYear => query.OrderBy(s => s.Series.Metadata.ReleaseYear),
|
||||
SortField.ReadProgress => query.OrderBy(s => s.Series.Progress.Where(p => p.SeriesId == s.Series.Id).Select(p => p.LastModified).Max()),
|
||||
_ => query
|
||||
};
|
||||
}
|
||||
|
|
@ -44,12 +45,13 @@ public static class BookmarkSort
|
|||
{
|
||||
query = sortOptions.SortField switch
|
||||
{
|
||||
SortField.SortName => query.OrderByDescending(s => s.series.SortName.ToLower()),
|
||||
SortField.CreatedDate => query.OrderByDescending(s => s.series.Created),
|
||||
SortField.LastModifiedDate => query.OrderByDescending(s => s.series.LastModified),
|
||||
SortField.LastChapterAdded => query.OrderByDescending(s => s.series.LastChapterAdded),
|
||||
SortField.TimeToRead => query.OrderByDescending(s => s.series.AvgHoursToRead),
|
||||
SortField.ReleaseYear => query.OrderByDescending(s => s.series.Metadata.ReleaseYear),
|
||||
SortField.SortName => query.OrderByDescending(s => s.Series.SortName.ToLower()),
|
||||
SortField.CreatedDate => query.OrderByDescending(s => s.Series.Created),
|
||||
SortField.LastModifiedDate => query.OrderByDescending(s => s.Series.LastModified),
|
||||
SortField.LastChapterAdded => query.OrderByDescending(s => s.Series.LastChapterAdded),
|
||||
SortField.TimeToRead => query.OrderByDescending(s => s.Series.AvgHoursToRead),
|
||||
SortField.ReleaseYear => query.OrderByDescending(s => s.Series.Metadata.ReleaseYear),
|
||||
SortField.ReadProgress => query.OrderByDescending(s => s.Series.Progress.Where(p => p.SeriesId == s.Series.Id).Select(p => p.LastModified).Max()),
|
||||
_ => query
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,6 +288,64 @@ public static class SeriesFilter
|
|||
return queryable.Where(s => ids.Contains(s.Id));
|
||||
}
|
||||
|
||||
public static IQueryable<Series> HasReadingDate(this IQueryable<Series> queryable, bool condition,
|
||||
FilterComparison comparison, DateTime? date, int userId)
|
||||
{
|
||||
if (!condition || !date.HasValue) return queryable;
|
||||
|
||||
var subQuery = queryable
|
||||
.Include(s => s.Progress)
|
||||
.Where(s => s.Progress != null)
|
||||
.Select(s => new
|
||||
{
|
||||
Series = s,
|
||||
MaxDate = s.Progress.Where(p => p != null && p.AppUserId == userId)
|
||||
.Select(p => (DateTime?) p.LastModified)
|
||||
.DefaultIfEmpty()
|
||||
.Max()
|
||||
})
|
||||
.Where(s => s.MaxDate != null)
|
||||
.AsEnumerable();
|
||||
|
||||
switch (comparison)
|
||||
{
|
||||
case FilterComparison.Equal:
|
||||
subQuery = subQuery.Where(s => s.MaxDate != null && s.MaxDate.Equals(date));
|
||||
break;
|
||||
case FilterComparison.IsAfter:
|
||||
case FilterComparison.GreaterThan:
|
||||
subQuery = subQuery.Where(s => s.MaxDate != null && s.MaxDate > date);
|
||||
break;
|
||||
case FilterComparison.GreaterThanEqual:
|
||||
subQuery = subQuery.Where(s => s.MaxDate != null && s.MaxDate >= date);
|
||||
break;
|
||||
case FilterComparison.IsBefore:
|
||||
case FilterComparison.LessThan:
|
||||
subQuery = subQuery.Where(s => s.MaxDate != null && s.MaxDate < date);
|
||||
break;
|
||||
case FilterComparison.LessThanEqual:
|
||||
subQuery = subQuery.Where(s => s.MaxDate != null && s.MaxDate <= date);
|
||||
break;
|
||||
case FilterComparison.NotEqual:
|
||||
subQuery = subQuery.Where(s => s.MaxDate != null && !s.MaxDate.Equals(date));
|
||||
break;
|
||||
case FilterComparison.Matches:
|
||||
case FilterComparison.Contains:
|
||||
case FilterComparison.NotContains:
|
||||
case FilterComparison.BeginsWith:
|
||||
case FilterComparison.EndsWith:
|
||||
case FilterComparison.IsInLast:
|
||||
case FilterComparison.IsNotInLast:
|
||||
case FilterComparison.MustContains:
|
||||
throw new KavitaException($"{comparison} not applicable for Series.ReadProgress");
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(comparison), comparison, null);
|
||||
}
|
||||
|
||||
var ids = subQuery.Select(s => s.Series.Id).ToList();
|
||||
return queryable.Where(s => ids.Contains(s.Id));
|
||||
}
|
||||
|
||||
public static IQueryable<Series> HasTags(this IQueryable<Series> queryable, bool condition,
|
||||
FilterComparison comparison, IList<int> tags)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public static class SeriesSort
|
|||
SortField.LastChapterAdded => query.OrderBy(s => s.LastChapterAdded),
|
||||
SortField.TimeToRead => query.OrderBy(s => s.AvgHoursToRead),
|
||||
SortField.ReleaseYear => query.OrderBy(s => s.Metadata.ReleaseYear),
|
||||
//SortField.ReadProgress => query.OrderBy()
|
||||
SortField.ReadProgress => query.OrderBy(s => s.Progress.Where(p => p.SeriesId == s.Id).Select(p => p.LastModified).Max()),
|
||||
_ => query
|
||||
};
|
||||
}
|
||||
|
|
@ -45,6 +45,7 @@ public static class SeriesSort
|
|||
SortField.LastChapterAdded => query.OrderByDescending(s => s.LastChapterAdded),
|
||||
SortField.TimeToRead => query.OrderByDescending(s => s.AvgHoursToRead),
|
||||
SortField.ReleaseYear => query.OrderByDescending(s => s.Metadata.ReleaseYear),
|
||||
SortField.ReadProgress => query.OrderByDescending(s => s.Progress.Where(p => p.SeriesId == s.Id).Select(p => p.LastModified).Max()),
|
||||
_ => query
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,12 +36,12 @@ public class AutoMapperProfiles : Profile
|
|||
public AutoMapperProfiles()
|
||||
{
|
||||
CreateMap<BookmarkSeriesPair, BookmarkDto>()
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.bookmark.Id))
|
||||
.ForMember(dest => dest.Page, opt => opt.MapFrom(src => src.bookmark.Page))
|
||||
.ForMember(dest => dest.VolumeId, opt => opt.MapFrom(src => src.bookmark.VolumeId))
|
||||
.ForMember(dest => dest.SeriesId, opt => opt.MapFrom(src => src.bookmark.SeriesId))
|
||||
.ForMember(dest => dest.ChapterId, opt => opt.MapFrom(src => src.bookmark.ChapterId))
|
||||
.ForMember(dest => dest.Series, opt => opt.MapFrom(src => src.series));
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Bookmark.Id))
|
||||
.ForMember(dest => dest.Page, opt => opt.MapFrom(src => src.Bookmark.Page))
|
||||
.ForMember(dest => dest.VolumeId, opt => opt.MapFrom(src => src.Bookmark.VolumeId))
|
||||
.ForMember(dest => dest.SeriesId, opt => opt.MapFrom(src => src.Bookmark.SeriesId))
|
||||
.ForMember(dest => dest.ChapterId, opt => opt.MapFrom(src => src.Bookmark.ChapterId))
|
||||
.ForMember(dest => dest.Series, opt => opt.MapFrom(src => src.Series));
|
||||
CreateMap<LibraryDto, Library>();
|
||||
CreateMap<Volume, VolumeDto>();
|
||||
CreateMap<MangaFile, MangaFileDto>();
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public static class FilterFieldValueConverter
|
|||
.ToList(), typeof(IList<int>)),
|
||||
FilterField.WantToRead => (bool.Parse(value), typeof(bool)),
|
||||
FilterField.ReadProgress => (int.Parse(value), typeof(int)),
|
||||
FilterField.ReadingDate => (DateTime.Parse(value), typeof(DateTime?)),
|
||||
FilterField.Formats => (value.Split(',')
|
||||
.Select(x => (MangaFormat) Enum.Parse(typeof(MangaFormat), x))
|
||||
.ToList(), typeof(IList<MangaFormat>)),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue