From 912a963a2bf7f9534e9395d1a2da8d910f249b5b Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 17 Jan 2026 15:58:00 +0100 Subject: Add folder-aware filter extensions and descendant query provider - Add FolderAwareFilterExtensions for LinkedChildren-based filtering - Add IDescendantQueryProvider interface for database-specific queries - Add MatchCriteria classes for folder filtering - Add SqliteDescendantQueryProvider implementation --- .../IDescendantQueryProvider.cs | 30 ++++++++++++++++++++++ .../MatchCriteria/FolderMatchCriteria.cs | 6 +++++ .../MatchCriteria/HasChapterImages.cs | 6 +++++ .../MatchCriteria/HasMediaStreamType.cs | 14 ++++++++++ .../MatchCriteria/HasSubtitles.cs | 6 +++++ 5 files changed, 62 insertions(+) create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Implementations/IDescendantQueryProvider.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/FolderMatchCriteria.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasChapterImages.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasMediaStreamType.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasSubtitles.cs (limited to 'src/Jellyfin.Database/Jellyfin.Database.Implementations') diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IDescendantQueryProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IDescendantQueryProvider.cs new file mode 100644 index 0000000000..9e3d510b9c --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IDescendantQueryProvider.cs @@ -0,0 +1,30 @@ +using System; +using System.Linq; +using Jellyfin.Database.Implementations.MatchCriteria; + +namespace Jellyfin.Database.Implementations; + +/// +/// Provider interface for descendant queries using recursive CTEs. +/// Each database provider implements this with provider-specific SQL. +/// +public interface IDescendantQueryProvider +{ + /// + /// Gets a queryable of all descendant IDs for a parent item. + /// Uses recursive CTE to traverse AncestorIds and LinkedChildren infinitely. + /// + /// Database context. + /// Parent item ID. + /// Queryable of descendant item IDs. + IQueryable GetAllDescendantIds(JellyfinDbContext context, Guid parentId); + + /// + /// Gets a queryable of all folder IDs that have any descendant matching the specified criteria. + /// Uses recursive CTE for infinite depth traversal. Can be used in LINQ .Contains() expressions. + /// + /// Database context. + /// The matching criteria to apply. + /// Queryable of folder IDs. + IQueryable GetFolderIdsMatching(JellyfinDbContext context, FolderMatchCriteria criteria); +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/FolderMatchCriteria.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/FolderMatchCriteria.cs new file mode 100644 index 0000000000..d9f2d91806 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/FolderMatchCriteria.cs @@ -0,0 +1,6 @@ +namespace Jellyfin.Database.Implementations.MatchCriteria; + +/// +/// Base type for folder matching criteria using discriminated union pattern. +/// +public abstract record FolderMatchCriteria; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasChapterImages.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasChapterImages.cs new file mode 100644 index 0000000000..3dd84bbd27 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasChapterImages.cs @@ -0,0 +1,6 @@ +namespace Jellyfin.Database.Implementations.MatchCriteria; + +/// +/// Matches folders containing descendants with chapter images. +/// +public sealed record HasChapterImages : FolderMatchCriteria; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasMediaStreamType.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasMediaStreamType.cs new file mode 100644 index 0000000000..68f2ca2786 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasMediaStreamType.cs @@ -0,0 +1,14 @@ +using Jellyfin.Database.Implementations.Entities; + +namespace Jellyfin.Database.Implementations.MatchCriteria; + +/// +/// Matches folders containing descendants with a specific media stream type and language. +/// +/// The type of media stream to match (Audio, Subtitle, etc.). +/// The language to match. +/// If not null, filters by internal (false) or external (true) streams. Only applicable to subtitles. +public sealed record HasMediaStreamType( + MediaStreamTypeEntity StreamType, + string Language, + bool? IsExternal = null) : FolderMatchCriteria; diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasSubtitles.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasSubtitles.cs new file mode 100644 index 0000000000..e50b9f3e12 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/MatchCriteria/HasSubtitles.cs @@ -0,0 +1,6 @@ +namespace Jellyfin.Database.Implementations.MatchCriteria; + +/// +/// Matches folders containing descendants with subtitles. +/// +public sealed record HasSubtitles : FolderMatchCriteria; -- cgit v1.2.3