aboutsummaryrefslogtreecommitdiff
path: root/src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs')
-rw-r--r--src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs43
1 files changed, 24 insertions, 19 deletions
diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs
index ac47f00a18..b821476390 100644
--- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs
+++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/DescendantQueryHelper.cs
@@ -32,23 +32,15 @@ public static class DescendantQueryHelper
{
ArgumentNullException.ThrowIfNull(context);
- var (closureRoots, linkRoots) = ResolveLinkedRoots(context, parentId);
-
- var hierarchyDescendants = ClosureDescendants(context, closureRoots);
-
- var linkedDescendants = context.LinkedChildren
- .WhereOneOrMany(linkRoots, e => e.ParentId)
- .Select(e => e.ChildId);
-
- return hierarchyDescendants
- .Concat(linkedDescendants)
+ return AllDescendants(context, [parentId])
.Where(e => !e.Equals(parentId))
.Distinct();
}
/// <summary>
/// Gets all descendant IDs for multiple parent items in a single traversal.
- /// Traverses AncestorIds and LinkedChildren, like <see cref="GetAllDescendantIds"/>.
+ /// Traverses AncestorIds and LinkedChildren, like <see cref="GetAllDescendantIds"/>, but resolves
+ /// the roots once for all seeds instead of once per seed.
/// </summary>
/// <param name="context">Database context.</param>
/// <param name="parentIds">Parent item IDs.</param>
@@ -63,10 +55,11 @@ public static class DescendantQueryHelper
return [];
}
- var seedSet = new HashSet<Guid>(parentIds);
- var descendants = TraverseHierarchyDown(context, seedSet);
+ var descendants = AllDescendants(context, parentIds)
+ .Distinct()
+ .ToHashSet();
- descendants.ExceptWith(seedSet);
+ descendants.ExceptWith(parentIds);
return descendants;
}
@@ -241,6 +234,18 @@ public static class DescendantQueryHelper
return query;
}
+ private static IQueryable<Guid> AllDescendants(JellyfinDbContext context, IReadOnlyList<Guid> parentIds)
+ {
+ var (closureRoots, linkRoots) = ResolveLinkedRoots(context, parentIds);
+
+ var linkedDescendants = context.LinkedChildren
+ .WhereOneOrMany(linkRoots, e => e.ParentId)
+ .Select(e => e.ChildId);
+
+ return ClosureDescendants(context, closureRoots)
+ .Concat(linkedDescendants);
+ }
+
private static IQueryable<Guid> ClosureDescendants(JellyfinDbContext context, IReadOnlyList<Guid> roots)
{
var direct = context.AncestorIds
@@ -311,12 +316,12 @@ public static class DescendantQueryHelper
// Resolves the roots the descendant sub-selects are anchored on: those contributing their closure,
// and those contributing their linked children.
- private static (List<Guid> ClosureRoots, List<Guid> LinkRoots) ResolveLinkedRoots(JellyfinDbContext context, Guid parentId)
+ private static (List<Guid> ClosureRoots, List<Guid> LinkRoots) ResolveLinkedRoots(JellyfinDbContext context, IReadOnlyList<Guid> parentIds)
{
- var closureRoots = new List<Guid> { parentId };
- var linkRoots = new List<Guid> { parentId };
- var visited = new HashSet<Guid> { parentId };
- var frontier = new List<Guid> { parentId };
+ var visited = new HashSet<Guid>(parentIds);
+ var closureRoots = visited.ToList();
+ var linkRoots = visited.ToList();
+ var frontier = visited.ToList();
while (frontier.Count != 0)
{