< 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
23%
Covered lines: 12
Uncovered lines: 39
Coverable lines: 51
Total lines: 98
Line coverage: 23.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 10/25/2025 - 12:09:58 AM Line coverage: 31.2% (10/32) Branch coverage: 20.6% (6/29) Total lines: 5711/18/2025 - 12:11:25 AM Line coverage: 28.5% (12/42) Branch coverage: 16.1% (5/31) Total lines: 711/19/2026 - 12:13:54 AM Line coverage: 23.5% (12/51) Branch coverage: 15.1% (5/33) Total lines: 98 10/25/2025 - 12:09:58 AM Line coverage: 31.2% (10/32) Branch coverage: 20.6% (6/29) Total lines: 5711/18/2025 - 12:11:25 AM Line coverage: 28.5% (12/42) Branch coverage: 16.1% (5/31) Total lines: 711/19/2026 - 12:13:54 AM Line coverage: 23.5% (12/51) Branch coverage: 15.1% (5/33) Total lines: 98

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
MapOrderByField(...)16.12%4173126.19%
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
 3using System;
 4using System.Linq;
 5using System.Linq.Expressions;
 6using Jellyfin.Data.Enums;
 7using Jellyfin.Database.Implementations;
 8using Jellyfin.Database.Implementations.Entities;
 9using Jellyfin.Extensions;
 10using MediaBrowser.Controller.Entities;
 11using Microsoft.EntityFrameworkCore;
 12
 13namespace Jellyfin.Server.Implementations.Item;
 14
 15/// <summary>
 16/// Static class for methods which maps types of ordering to their respecting ordering functions.
 17/// </summary>
 18public static class OrderMapper
 19{
 20    /// <summary>
 21    /// Creates Func to be executed later with a given BaseItemEntity input for sorting items on query.
 22    /// </summary>
 23    /// <param name="sortBy">Item property to sort by.</param>
 24    /// <param name="query">Context Query.</param>
 25    /// <param name="jellyfinDbContext">Context.</param>
 26    /// <returns>Func to be executed later for sorting query.</returns>
 27    public static Expression<Func<BaseItemEntity, object?>> MapOrderByField(ItemSortBy sortBy, InternalItemsQuery query,
 28    {
 15629        return (sortBy, query.User) switch
 15630        {
 031            (ItemSortBy.AirTime, _) => e => e.SortName, // TODO
 032            (ItemSortBy.Runtime, _) => e => e.RunTimeTicks,
 6633            (ItemSortBy.Random, _) => e => EF.Functions.Random(),
 134            (ItemSortBy.DatePlayed, _) => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.LastPla
 035            (ItemSortBy.PlayCount, _) => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.PlayCoun
 036            (ItemSortBy.IsFavoriteOrLiked, _) => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.
 4437            (ItemSortBy.IsFolder, _) => e => e.IsFolder,
 038            (ItemSortBy.IsPlayed, _) => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.Played,
 039            (ItemSortBy.IsUnplayed, _) => e => !e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.Played
 040            (ItemSortBy.DateLastContentAdded, _) => e => e.DateLastMediaAdded,
 041            (ItemSortBy.Artist, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Artist).Select(f =
 042            (ItemSortBy.AlbumArtist, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.AlbumArtist).
 043            (ItemSortBy.Studio, _) => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Studios).Select(f 
 044            (ItemSortBy.OfficialRating, _) => e => e.InheritedParentalRatingValue,
 045            (ItemSortBy.SeriesSortName, _) => e => e.SeriesName,
 046            (ItemSortBy.Album, _) => e => e.Album,
 047            (ItemSortBy.DateCreated, _) => e => e.DateCreated,
 148            (ItemSortBy.PremiereDate, _) => e => (e.PremiereDate ?? (e.ProductionYear.HasValue ? DateTime.MinValue.AddYe
 049            (ItemSortBy.StartDate, _) => e => e.StartDate,
 050            (ItemSortBy.Name, _) => e => e.CleanName,
 051            (ItemSortBy.CommunityRating, _) => e => e.CommunityRating,
 052            (ItemSortBy.ProductionYear, _) => e => e.ProductionYear,
 053            (ItemSortBy.CriticRating, _) => e => e.CriticRating,
 054            (ItemSortBy.VideoBitRate, _) => e => e.TotalBitrate,
 055            (ItemSortBy.ParentIndexNumber, _) => e => e.ParentIndexNumber,
 056            (ItemSortBy.IndexNumber, _) => e => e.IndexNumber,
 057            (ItemSortBy.SeriesDatePlayed, not null) => e =>
 058                            jellyfinDbContext.BaseItems
 059                                .Where(w => w.SeriesPresentationUniqueKey == e.PresentationUniqueKey)
 060                                .Join(jellyfinDbContext.UserData.Where(w => w.UserId == query.User.Id && w.Played), f =>
 061                                .Max(f => f),
 062            (ItemSortBy.SeriesDatePlayed, null) => e => jellyfinDbContext.BaseItems.Where(w => w.SeriesPresentationUniqu
 063                                .Join(jellyfinDbContext.UserData.Where(w => w.Played), f => f.Id, f => f.ItemId, (item, 
 064                                .Max(f => f),
 15665            // ItemSortBy.SeriesDatePlayed => e => jellyfinDbContext.UserData
 15666            //     .Where(u => u.Item!.SeriesPresentationUniqueKey == e.PresentationUniqueKey && u.Played)
 15667            //     .Max(f => f.LastPlayedDate),
 15668            // ItemSortBy.AiredEpisodeOrder => "AiredEpisodeOrder",
 4469            _ => e => e.SortName
 15670        };
 71    }
 72
 73    /// <summary>
 74    /// Creates an expression to order search results by match quality.
 75    /// Prioritizes: exact match (0) > prefix match with word boundary (1) > prefix match (2) > contains (3).
 76    /// </summary>
 77    /// <param name="searchTerm">The search term to match against.</param>
 78    /// <returns>An expression that returns an integer representing match quality (lower is better).</returns>
 79    public static Expression<Func<BaseItemEntity, int>> MapSearchRelevanceOrder(string searchTerm)
 80    {
 081        var cleanSearchTerm = GetCleanValue(searchTerm);
 082        var searchPrefix = cleanSearchTerm + " ";
 083        return e =>
 084            e.CleanName == cleanSearchTerm ? 0 :
 085            e.CleanName!.StartsWith(searchPrefix) ? 1 :
 086            e.CleanName!.StartsWith(cleanSearchTerm) ? 2 : 3;
 87    }
 88
 89    private static string GetCleanValue(string value)
 90    {
 091        if (string.IsNullOrWhiteSpace(value))
 92        {
 093            return value;
 94        }
 95
 096        return value.RemoveDiacritics().ToLowerInvariant();
 97    }
 98}