< Summary - Jellyfin

Information
Class: Jellyfin.Server.Implementations.Item.OrderMapper
Assembly: Jellyfin.Server.Implementations
File(s): /srv/git/jellyfin/Jellyfin.Server.Implementations/Item/OrderMapper.cs
Line coverage
18%
Covered lines: 10
Uncovered lines: 44
Coverable lines: 54
Total lines: 105
Line coverage: 18.5%
Branch coverage
15%
Covered branches: 5
Total branches: 33
Branch coverage: 15.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 1/23/2026 - 12:11:06 AM Line coverage: 23.5% (12/51) Branch coverage: 15.1% (5/33) Total lines: 985/4/2026 - 12:15:16 AM Line coverage: 18.5% (10/54) Branch coverage: 15.1% (5/33) Total lines: 105 1/23/2026 - 12:11:06 AM Line coverage: 23.5% (12/51) Branch coverage: 15.1% (5/33) Total lines: 985/4/2026 - 12:15:16 AM Line coverage: 18.5% (10/54) Branch coverage: 15.1% (5/33) Total lines: 105

Coverage delta

Coverage delta 5 -5

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
MapOrderByField(...)16.12%4783122.5%
MapSearchRelevanceOrder(...)100%210%
GetCleanValue(...)0%620%

File(s)

/srv/git/jellyfin/Jellyfin.Server.Implementations/Item/OrderMapper.cs

#LineLine coverage
 1#pragma warning disable RS0030 // Do not use banned APIs
 2#pragma warning disable CA1304 // Specify CultureInfo
 3#pragma warning disable CA1311 // Specify a culture or use an invariant version
 4#pragma warning disable CA1862 // Use the 'StringComparison' method overloads to perform case-insensitive string compari
 5
 6using System;
 7using System.Linq;
 8using System.Linq.Expressions;
 9using Jellyfin.Data.Enums;
 10using Jellyfin.Database.Implementations;
 11using Jellyfin.Database.Implementations.Entities;
 12using Jellyfin.Extensions;
 13using MediaBrowser.Controller.Entities;
 14using Microsoft.EntityFrameworkCore;
 15
 16namespace Jellyfin.Server.Implementations.Item;
 17
 18/// <summary>
 19/// Static class for methods which maps types of ordering to their respecting ordering functions.
 20/// </summary>
 21public static class OrderMapper
 22{
 23    /// <summary>
 24    /// Creates Func to be executed later with a given BaseItemEntity input for sorting items on query.
 25    /// </summary>
 26    /// <param name="sortBy">Item property to sort by.</param>
 27    /// <param name="query">Context Query.</param>
 28    /// <param name="jellyfinDbContext">Context.</param>
 29    /// <returns>Func to be executed later for sorting query.</returns>
 30    public static Expression<Func<BaseItemEntity, object?>> MapOrderByField(ItemSortBy sortBy, InternalItemsQuery query,
 31    {
 15432        return (sortBy, query.User) switch
 15433        {
 034            (ItemSortBy.AirTime, _) => e => e.SortName,
 035            (ItemSortBy.Runtime, _) => e => e.RunTimeTicks,
 6236            (ItemSortBy.Random, _) => e => EF.Functions.Random(),
 137            (ItemSortBy.DatePlayed, _) => e => e.UserData!.Where(f => f.UserId.Equals(query.User!.Id)).OrderBy(f => f.Cu
 038            (ItemSortBy.PlayCount, _) => e => e.UserData!.Where(f => f.UserId.Equals(query.User!.Id)).OrderBy(f => f.Cus
 039            (ItemSortBy.IsFavoriteOrLiked, _) => e => e.UserData!.Where(f => f.UserId.Equals(query.User!.Id)).OrderBy(f 
 4240            (ItemSortBy.IsFolder, _) => e => e.IsFolder,
 041            (ItemSortBy.IsPlayed, _) => e => e.UserData!.Where(f => f.UserId.Equals(query.User!.Id)).OrderBy(f => f.Cust
 042            (ItemSortBy.IsUnplayed, _) => e => !e.UserData!.Where(f => f.UserId.Equals(query.User!.Id)).OrderBy(f => f.C
 043            (ItemSortBy.DateLastContentAdded, _) => e => e.DateLastMediaAdded,
 044            (ItemSortBy.Artist, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Artist).OrderBy(f 
 045            (ItemSortBy.AlbumArtist, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.AlbumArtist).
 046            (ItemSortBy.Studio, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Studios).OrderBy(f
 047            (ItemSortBy.OfficialRating, _) => e => e.InheritedParentalRatingValue,
 048            (ItemSortBy.SeriesSortName, _) => e => e.SeriesName,
 049            (ItemSortBy.Album, _) => e => e.Album,
 050            (ItemSortBy.DateCreated, _) => e => e.DateCreated,
 151            (ItemSortBy.PremiereDate, _) => e => (e.PremiereDate ?? (e.ProductionYear.HasValue ? DateTime.MinValue.AddYe
 052            (ItemSortBy.StartDate, _) => e => e.StartDate,
 053            (ItemSortBy.Name, _) => e => e.CleanName,
 054            (ItemSortBy.CommunityRating, _) => e => e.CommunityRating,
 055            (ItemSortBy.ProductionYear, _) => e => e.ProductionYear,
 056            (ItemSortBy.CriticRating, _) => e => e.CriticRating,
 057            (ItemSortBy.VideoBitRate, _) => e => e.TotalBitrate,
 058            (ItemSortBy.ParentIndexNumber, _) => e => e.ParentIndexNumber,
 059            (ItemSortBy.IndexNumber, _) => e => e.IndexNumber,
 15460            // SeriesDatePlayed is normally handled via pre-aggregated join in ApplySeriesDatePlayedOrder.
 15461            // This correlated subquery fallback is only reached when combined with search.
 062            (ItemSortBy.SeriesDatePlayed, not null) => e =>
 063                jellyfinDbContext.UserData
 064                    .Where(w => w.UserId == query.User.Id && w.Played && w.Item!.SeriesPresentationUniqueKey == e.Presen
 065                    .Max(f => f.LastPlayedDate),
 066            (ItemSortBy.SeriesDatePlayed, null) => e =>
 067                jellyfinDbContext.UserData
 068                    .Where(w => w.Played && w.Item!.SeriesPresentationUniqueKey == e.PresentationUniqueKey)
 069                    .Max(f => f.LastPlayedDate),
 4870            _ => e => e.SortName
 15471        };
 72    }
 73
 74    /// <summary>
 75    /// Creates an expression to order search results by match quality.
 76    /// Prioritizes: exact match (0) > prefix match with word boundary (1) > prefix match (2) > contains (3).
 77    /// Considers both CleanName and OriginalTitle for matching.
 78    /// </summary>
 79    /// <param name="searchTerm">The search term to match against.</param>
 80    /// <returns>An expression that returns an integer representing match quality (lower is better).</returns>
 81    public static Expression<Func<BaseItemEntity, int>> MapSearchRelevanceOrder(string searchTerm)
 82    {
 083        var cleanSearchTerm = GetCleanValue(searchTerm);
 084        var searchPrefix = cleanSearchTerm + " ";
 085        var originalSearchLower = searchTerm.ToLowerInvariant();
 086        var originalSearchPrefix = originalSearchLower + " ";
 087        return e =>
 088            // Exact match on CleanName or OriginalTitle
 089            (e.CleanName == cleanSearchTerm || (e.OriginalTitle != null && e.OriginalTitle.ToLower() == originalSearchLo
 090            // Prefix match with word boundary
 091            (e.CleanName!.StartsWith(searchPrefix) || (e.OriginalTitle != null && e.OriginalTitle.ToLower().StartsWith(o
 092            // Prefix match
 093            (e.CleanName!.StartsWith(cleanSearchTerm) || (e.OriginalTitle != null && e.OriginalTitle.ToLower().StartsWit
 94    }
 95
 96    private static string GetCleanValue(string value)
 97    {
 098        if (string.IsNullOrWhiteSpace(value))
 99        {
 0100            return value;
 101        }
 102
 0103        return value.RemoveDiacritics().ToLowerInvariant();
 104    }
 105}