From de336d307473f8621f265b67931834db450c8f8a Mon Sep 17 00:00:00 2001 From: Marti Markov Date: Thu, 1 Oct 2026 18:37:22 +0100 Subject: [PATCH] Compare person names without regard to case in the letter range filters --- .../Item/PeopleRepository.cs | 4 +- .../Item/PeopleRepositoryNameRangeTests.cs | 53 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryNameRangeTests.cs diff --git a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs index fcddc09ad9..4c5271d9bc 100644 --- a/Jellyfin.Server.Implementations/Item/PeopleRepository.cs +++ b/Jellyfin.Server.Implementations/Item/PeopleRepository.cs @@ -477,12 +477,12 @@ public class PeopleRepository(IDbContextFactory dbProvider, I if (!string.IsNullOrWhiteSpace(filter.NameLessThan)) { - query = query.Where(e => e.Name.CompareTo(filter.NameLessThan.ToLowerInvariant()) < 0); + query = query.Where(e => e.Name.ToLower().CompareTo(filter.NameLessThan.ToLowerInvariant()) < 0); } if (!string.IsNullOrWhiteSpace(filter.NameStartsWithOrGreater)) { - query = query.Where(e => e.Name.CompareTo(filter.NameStartsWithOrGreater.ToLowerInvariant()) >= 0); + query = query.Where(e => e.Name.ToLower().CompareTo(filter.NameStartsWithOrGreater.ToLowerInvariant()) >= 0); } return query; diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryNameRangeTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryNameRangeTests.cs new file mode 100644 index 0000000000..754b388ecf --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryNameRangeTests.cs @@ -0,0 +1,53 @@ +using System; +using System.Linq; +using Emby.Server.Implementations.Data; +using Jellyfin.Database.Implementations.Entities; +using Jellyfin.Server.Implementations.Item; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Persistence; +using Moq; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.Item; + +/// +/// The letter picker on the person list filters with NameStartsWithOrGreater and NameLessThan. +/// Names keep the case a metadata provider wrote them in, so the range has to ignore case the same way +/// the list is sorted, or a capitalised name lands before every lowercase bound. +/// +public sealed class PeopleRepositoryNameRangeTests : SqliteDbTestFixture +{ + private readonly PeopleRepository _repository; + + public PeopleRepositoryNameRangeTests() + { + using (var context = CreateDbContext()) + { + foreach (var name in new[] { "50 Cent", "alpha centauri", "Brad Pitt", "bob dylan", "Zoe Saldana" }) + { + context.Peoples.Add(new People { Id = Guid.NewGuid(), Name = name, PersonType = "Actor" }); + } + + context.SaveChanges(); + } + + _repository = new PeopleRepository(CreateDbContextFactory(), new ItemTypeLookup(), new Mock().Object); + } + + [Theory] + [InlineData(null, "A", new[] { "50 Cent" })] + [InlineData(null, "C", new[] { "50 Cent", "alpha centauri", "bob dylan", "Brad Pitt" })] + [InlineData("B", "C", new[] { "bob dylan", "Brad Pitt" })] + [InlineData("Y", null, new[] { "Zoe Saldana" })] + public void GetPeople_NameRange_IgnoresCase(string? nameStartsWithOrGreater, string? nameLessThan, string[] expected) + { + var result = _repository.GetPeople(new InternalPeopleQuery + { + NameStartsWithOrGreater = nameStartsWithOrGreater, + NameLessThan = nameLessThan + }); + + Assert.Equal(expected, result.Items.Select(p => p.Name)); + Assert.Equal(expected.Length, result.TotalRecordCount); + } +}