< 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
21%
Covered lines: 13
Uncovered lines: 48
Coverable lines: 61
Total lines: 112
Line coverage: 21.3%
Branch coverage
17%
Covered branches: 6
Total branches: 35
Branch coverage: 17.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 4/8/2026 - 12:11:47 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: 1057/6/2026 - 12:16:28 AM Line coverage: 21.3% (13/61) Branch coverage: 17.1% (6/35) Total lines: 112 4/8/2026 - 12:11:47 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: 1057/6/2026 - 12:16:28 AM Line coverage: 21.3% (13/61) Branch coverage: 17.1% (6/35) Total lines: 112

Coverage delta

Coverage delta 5 -5

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
MapOrderByField(...)18.18%4833325.53%
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    {
 16832        return (sortBy, query.User) switch
 16833        {
 034            (ItemSortBy.AirTime, _) => e => e.SortName,
 035            (ItemSortBy.Runtime, _) => e => e.RunTimeTicks,
 6836            (ItemSortBy.Random, _) => e => EF.Functions.Random(),
 137            (ItemSortBy.DatePlayed, not null) => e =>
 138                jellyfinDbContext.UserData
 139                    .Where(w => w.UserId == query.User.Id && (w.ItemId == e.Id || w.Item!.PrimaryVersionId == e.Id))
 140                    .Max(f => f.LastPlayedDate),
 041            (ItemSortBy.DatePlayed, null) => e =>
 042                jellyfinDbContext.UserData
 043                    .Where(w => w.ItemId == e.Id || w.Item!.PrimaryVersionId == e.Id)
 044                    .Max(f => f.LastPlayedDate),
 045            (ItemSortBy.PlayCount, _) => e => e.UserData!.Where(f => f.UserId.Equals(query.User!.Id)).OrderBy(f => f.Cus
 046            (ItemSortBy.IsFavoriteOrLiked, _) => e => e.UserData!.Where(f => f.UserId.Equals(query.User!.Id)).OrderBy(f 
 4647            (ItemSortBy.IsFolder, _) => e => e.IsFolder,
 048            (ItemSortBy.IsPlayed, _) => e => e.UserData!.Where(f => f.UserId.Equals(query.User!.Id)).OrderBy(f => f.Cust
 049            (ItemSortBy.IsUnplayed, _) => e => !e.UserData!.Where(f => f.UserId.Equals(query.User!.Id)).OrderBy(f => f.C
 050            (ItemSortBy.DateLastContentAdded, _) => e => e.DateLastMediaAdded,
 051            (ItemSortBy.Artist, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Artist).OrderBy(f 
 052            (ItemSortBy.AlbumArtist, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.AlbumArtist).
 053            (ItemSortBy.Studio, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Studios).OrderBy(f
 054            (ItemSortBy.OfficialRating, _) => e => e.InheritedParentalRatingValue,
 055            (ItemSortBy.SeriesSortName, _) => e => e.SeriesName,
 056            (ItemSortBy.Album, _) => e => e.Album,
 057            (ItemSortBy.DateCreated, _) => e => e.DateCreated,
 158            (ItemSortBy.PremiereDate, _) => e => e.PremiereDate ?? (e.ProductionYear.HasValue ? DateTime.MinValue.AddYea
 059            (ItemSortBy.StartDate, _) => e => e.StartDate,
 060            (ItemSortBy.Name, _) => e => e.SortName,
 061            (ItemSortBy.CommunityRating, _) => e => e.CommunityRating,
 062            (ItemSortBy.ProductionYear, _) => e => e.ProductionYear,
 063            (ItemSortBy.CriticRating, _) => e => e.CriticRating,
 064            (ItemSortBy.VideoBitRate, _) => e => e.TotalBitrate,
 065            (ItemSortBy.ParentIndexNumber, _) => e => e.ParentIndexNumber,
 066            (ItemSortBy.IndexNumber, _) => e => e.IndexNumber,
 16867            // SeriesDatePlayed is normally handled via pre-aggregated join in ApplySeriesDatePlayedOrder.
 16868            // This correlated subquery fallback is only reached when combined with search.
 069            (ItemSortBy.SeriesDatePlayed, not null) => e =>
 070                jellyfinDbContext.UserData
 071                    .Where(w => w.UserId == query.User.Id && w.Played && w.Item!.SeriesPresentationUniqueKey == e.Presen
 072                    .Max(f => f.LastPlayedDate),
 073            (ItemSortBy.SeriesDatePlayed, null) => e =>
 074                jellyfinDbContext.UserData
 075                    .Where(w => w.Played && w.Item!.SeriesPresentationUniqueKey == e.PresentationUniqueKey)
 076                    .Max(f => f.LastPlayedDate),
 5277            _ => e => e.SortName
 16878        };
 79    }
 80
 81    /// <summary>
 82    /// Creates an expression to order search results by match quality.
 83    /// Prioritizes: exact match (0) > prefix match with word boundary (1) > prefix match (2) > contains (3).
 84    /// Considers both CleanName and OriginalTitle for matching.
 85    /// </summary>
 86    /// <param name="searchTerm">The search term to match against.</param>
 87    /// <returns>An expression that returns an integer representing match quality (lower is better).</returns>
 88    public static Expression<Func<BaseItemEntity, int>> MapSearchRelevanceOrder(string searchTerm)
 89    {
 090        var cleanSearchTerm = GetCleanValue(searchTerm);
 091        var searchPrefix = cleanSearchTerm + " ";
 092        var originalSearchLower = searchTerm.ToLowerInvariant();
 093        var originalSearchPrefix = originalSearchLower + " ";
 094        return e =>
 095            // Exact match on CleanName or OriginalTitle
 096            (e.CleanName == cleanSearchTerm || (e.OriginalTitle != null && e.OriginalTitle.ToLower() == originalSearchLo
 097            // Prefix match with word boundary
 098            (e.CleanName!.StartsWith(searchPrefix) || (e.OriginalTitle != null && e.OriginalTitle.ToLower().StartsWith(o
 099            // Prefix match
 0100            (e.CleanName!.StartsWith(cleanSearchTerm) || (e.OriginalTitle != null && e.OriginalTitle.ToLower().StartsWit
 101    }
 102
 103    private static string GetCleanValue(string value)
 104    {
 0105        if (string.IsNullOrWhiteSpace(value))
 106        {
 0107            return value;
 108        }
 109
 0110        return value.RemoveDiacritics().ToLowerInvariant();
 111    }
 112}