Browse Source

Backport pull request #15413 from jellyfin/release-10.11.z

Fixed missing sort argument

Original-merge: 91c3b1617e06283c88f36bc63046b99c993cb774

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Bond_009 <bond.009@outlook.com>
JPVenson 3 days ago
parent
commit
74c9629372

+ 10 - 7
Jellyfin.Server.Implementations/Item/BaseItemRepository.cs

@@ -275,6 +275,7 @@ public sealed class BaseItemRepository
         }
 
         dbQuery = ApplyQueryPaging(dbQuery, filter);
+        dbQuery = ApplyNavigations(dbQuery, filter);
 
         result.Items = dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserializeBaseItem(w, filter.SkipDeserialization)).ToArray();
         result.StartIndex = filter.StartIndex ?? 0;
@@ -294,6 +295,7 @@ public sealed class BaseItemRepository
 
         dbQuery = ApplyGroupingFilter(context, dbQuery, filter);
         dbQuery = ApplyQueryPaging(dbQuery, filter);
+        dbQuery = ApplyNavigations(dbQuery, filter);
 
         return dbQuery.AsEnumerable().Where(e => e is not null).Select(w => DeserializeBaseItem(w, filter.SkipDeserialization)).ToArray();
     }
@@ -337,6 +339,8 @@ public sealed class BaseItemRepository
         mainquery = ApplyGroupingFilter(context, mainquery, filter);
         mainquery = ApplyQueryPaging(mainquery, filter);
 
+        mainquery = ApplyNavigations(mainquery, filter);
+
         return mainquery.AsEnumerable().Where(e => e is not null).Select(w => DeserializeBaseItem(w, filter.SkipDeserialization)).ToArray();
     }
 
@@ -399,9 +403,7 @@ public sealed class BaseItemRepository
             dbQuery = dbQuery.Distinct();
         }
 
-        dbQuery = ApplyOrder(dbQuery, filter);
-
-        dbQuery = ApplyNavigations(dbQuery, filter);
+        dbQuery = ApplyOrder(dbQuery, filter, context);
 
         return dbQuery;
     }
@@ -446,6 +448,7 @@ public sealed class BaseItemRepository
         dbQuery = TranslateQuery(dbQuery, context, filter);
         dbQuery = ApplyGroupingFilter(context, dbQuery, filter);
         dbQuery = ApplyQueryPaging(dbQuery, filter);
+        dbQuery = ApplyNavigations(dbQuery, filter);
         return dbQuery;
     }
 
@@ -1252,7 +1255,7 @@ public sealed class BaseItemRepository
             .AsSingleQuery()
             .Where(e => masterQuery.Contains(e.Id));
 
-        query = ApplyOrder(query, filter);
+        query = ApplyOrder(query, filter, context);
 
         var result = new QueryResult<(BaseItemDto, ItemCounts?)>();
         if (filter.EnableTotalRecordCount)
@@ -1518,7 +1521,7 @@ public sealed class BaseItemRepository
             || query.IncludeItemTypes.Contains(BaseItemKind.Season);
     }
 
-    private IQueryable<BaseItemEntity> ApplyOrder(IQueryable<BaseItemEntity> query, InternalItemsQuery filter)
+    private IQueryable<BaseItemEntity> ApplyOrder(IQueryable<BaseItemEntity> query, InternalItemsQuery filter, JellyfinDbContext context)
     {
         var orderBy = filter.OrderBy;
         var hasSearch = !string.IsNullOrEmpty(filter.SearchTerm);
@@ -1537,7 +1540,7 @@ public sealed class BaseItemRepository
         var firstOrdering = orderBy.FirstOrDefault();
         if (firstOrdering != default)
         {
-            var expression = OrderMapper.MapOrderByField(firstOrdering.OrderBy, filter);
+            var expression = OrderMapper.MapOrderByField(firstOrdering.OrderBy, filter, context);
             if (firstOrdering.SortOrder == SortOrder.Ascending)
             {
                 orderedQuery = query.OrderBy(expression);
@@ -1562,7 +1565,7 @@ public sealed class BaseItemRepository
 
         foreach (var item in orderBy.Skip(1))
         {
-            var expression = OrderMapper.MapOrderByField(item.OrderBy, filter);
+            var expression = OrderMapper.MapOrderByField(item.OrderBy, filter, context);
             if (item.SortOrder == SortOrder.Ascending)
             {
                 orderedQuery = orderedQuery!.ThenBy(expression);

+ 43 - 29
Jellyfin.Server.Implementations/Item/OrderMapper.cs

@@ -1,7 +1,10 @@
+#pragma warning disable RS0030 // Do not use banned APIs
+
 using System;
 using System.Linq;
 using System.Linq.Expressions;
 using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations;
 using Jellyfin.Database.Implementations.Entities;
 using MediaBrowser.Controller.Entities;
 using Microsoft.EntityFrameworkCore;
@@ -18,39 +21,50 @@ public static class OrderMapper
     /// </summary>
     /// <param name="sortBy">Item property to sort by.</param>
     /// <param name="query">Context Query.</param>
+    /// <param name="jellyfinDbContext">Context.</param>
     /// <returns>Func to be executed later for sorting query.</returns>
-    public static Expression<Func<BaseItemEntity, object?>> MapOrderByField(ItemSortBy sortBy, InternalItemsQuery query)
+    public static Expression<Func<BaseItemEntity, object?>> MapOrderByField(ItemSortBy sortBy, InternalItemsQuery query, JellyfinDbContext jellyfinDbContext)
     {
-        return sortBy switch
+        return (sortBy, query.User) switch
         {
-            ItemSortBy.AirTime => e => e.SortName, // TODO
-            ItemSortBy.Runtime => e => e.RunTimeTicks,
-            ItemSortBy.Random => e => EF.Functions.Random(),
-            ItemSortBy.DatePlayed => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.LastPlayedDate,
-            ItemSortBy.PlayCount => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.PlayCount,
-            ItemSortBy.IsFavoriteOrLiked => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.IsFavorite,
-            ItemSortBy.IsFolder => e => e.IsFolder,
-            ItemSortBy.IsPlayed => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.Played,
-            ItemSortBy.IsUnplayed => e => !e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.Played,
-            ItemSortBy.DateLastContentAdded => e => e.DateLastMediaAdded,
-            ItemSortBy.Artist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Artist).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
-            ItemSortBy.AlbumArtist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.AlbumArtist).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
-            ItemSortBy.Studio => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Studios).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
-            ItemSortBy.OfficialRating => e => e.InheritedParentalRatingValue,
-            // ItemSortBy.SeriesDatePlayed => "(Select MAX(LastPlayedDate) from TypedBaseItems B" + GetJoinUserDataText(query) + " where Played=1 and B.SeriesPresentationUniqueKey=A.PresentationUniqueKey)",
-            ItemSortBy.SeriesSortName => e => e.SeriesName,
+            (ItemSortBy.AirTime, _) => e => e.SortName, // TODO
+            (ItemSortBy.Runtime, _) => e => e.RunTimeTicks,
+            (ItemSortBy.Random, _) => e => EF.Functions.Random(),
+            (ItemSortBy.DatePlayed, _) => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.LastPlayedDate,
+            (ItemSortBy.PlayCount, _) => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.PlayCount,
+            (ItemSortBy.IsFavoriteOrLiked, _) => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.IsFavorite,
+            (ItemSortBy.IsFolder, _) => e => e.IsFolder,
+            (ItemSortBy.IsPlayed, _) => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.Played,
+            (ItemSortBy.IsUnplayed, _) => e => !e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.Played,
+            (ItemSortBy.DateLastContentAdded, _) => e => e.DateLastMediaAdded,
+            (ItemSortBy.Artist, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Artist).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
+            (ItemSortBy.AlbumArtist, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.AlbumArtist).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
+            (ItemSortBy.Studio, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Studios).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
+            (ItemSortBy.OfficialRating, _) => e => e.InheritedParentalRatingValue,
+            (ItemSortBy.SeriesSortName, _) => e => e.SeriesName,
+            (ItemSortBy.Album, _) => e => e.Album,
+            (ItemSortBy.DateCreated, _) => e => e.DateCreated,
+            (ItemSortBy.PremiereDate, _) => e => (e.PremiereDate ?? (e.ProductionYear.HasValue ? DateTime.MinValue.AddYears(e.ProductionYear.Value - 1) : null)),
+            (ItemSortBy.StartDate, _) => e => e.StartDate,
+            (ItemSortBy.Name, _) => e => e.CleanName,
+            (ItemSortBy.CommunityRating, _) => e => e.CommunityRating,
+            (ItemSortBy.ProductionYear, _) => e => e.ProductionYear,
+            (ItemSortBy.CriticRating, _) => e => e.CriticRating,
+            (ItemSortBy.VideoBitRate, _) => e => e.TotalBitrate,
+            (ItemSortBy.ParentIndexNumber, _) => e => e.ParentIndexNumber,
+            (ItemSortBy.IndexNumber, _) => e => e.IndexNumber,
+            (ItemSortBy.SeriesDatePlayed, not null) => e =>
+                            jellyfinDbContext.BaseItems
+                                .Where(w => w.SeriesPresentationUniqueKey == e.PresentationUniqueKey)
+                                .Join(jellyfinDbContext.UserData.Where(w => w.UserId == query.User.Id && w.Played), f => f.Id, f => f.ItemId, (item, userData) => userData.LastPlayedDate)
+                                .Max(f => f),
+            (ItemSortBy.SeriesDatePlayed, null) => e => jellyfinDbContext.BaseItems.Where(w => w.SeriesPresentationUniqueKey == e.PresentationUniqueKey)
+                                .Join(jellyfinDbContext.UserData.Where(w => w.Played), f => f.Id, f => f.ItemId, (item, userData) => userData.LastPlayedDate)
+                                .Max(f => f),
+            // ItemSortBy.SeriesDatePlayed => e => jellyfinDbContext.UserData
+            //     .Where(u => u.Item!.SeriesPresentationUniqueKey == e.PresentationUniqueKey && u.Played)
+            //     .Max(f => f.LastPlayedDate),
             // ItemSortBy.AiredEpisodeOrder => "AiredEpisodeOrder",
-            ItemSortBy.Album => e => e.Album,
-            ItemSortBy.DateCreated => e => e.DateCreated,
-            ItemSortBy.PremiereDate => e => (e.PremiereDate ?? (e.ProductionYear.HasValue ? DateTime.MinValue.AddYears(e.ProductionYear.Value - 1) : null)),
-            ItemSortBy.StartDate => e => e.StartDate,
-            ItemSortBy.Name => e => e.CleanName,
-            ItemSortBy.CommunityRating => e => e.CommunityRating,
-            ItemSortBy.ProductionYear => e => e.ProductionYear,
-            ItemSortBy.CriticRating => e => e.CriticRating,
-            ItemSortBy.VideoBitRate => e => e.TotalBitrate,
-            ItemSortBy.ParentIndexNumber => e => e.ParentIndexNumber,
-            ItemSortBy.IndexNumber => e => e.IndexNumber,
             _ => e => e.SortName
         };
     }

+ 1 - 1
tests/Jellyfin.Server.Implementations.Tests/Item/OrderMapperTests.cs

@@ -12,7 +12,7 @@ public class OrderMapperTests
     [Fact]
     public void ShouldReturnMappedOrderForSortingByPremierDate()
     {
-        var orderFunc = OrderMapper.MapOrderByField(ItemSortBy.PremiereDate, new InternalItemsQuery()).Compile();
+        var orderFunc = OrderMapper.MapOrderByField(ItemSortBy.PremiereDate, new InternalItemsQuery(), null!).Compile();
 
         var expectedDate = new DateTime(1, 2, 3);
         var expectedProductionYearDate = new DateTime(4, 1, 1);