Explorar o código

Merge pull request #4274 from barronpm/activitylog-query

Rewrite Activity Log Backend
Anthony Lavado %!s(int64=4) %!d(string=hai) anos
pai
achega
ecabcff8f0

+ 10 - 10
Jellyfin.Api/Controllers/ActivityLogController.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
-using System.Linq;
+using System.Threading.Tasks;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Constants;
-using Jellyfin.Data.Entities;
+using Jellyfin.Data.Queries;
 using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Authorization;
@@ -39,19 +39,19 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="QueryResult{ActivityLogEntry}"/> containing the log entries.</returns>
         /// <returns>A <see cref="QueryResult{ActivityLogEntry}"/> containing the log entries.</returns>
         [HttpGet("Entries")]
         [HttpGet("Entries")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status200OK)]
-        public ActionResult<QueryResult<ActivityLogEntry>> GetLogEntries(
+        public async Task<ActionResult<QueryResult<ActivityLogEntry>>> GetLogEntries(
             [FromQuery] int? startIndex,
             [FromQuery] int? startIndex,
             [FromQuery] int? limit,
             [FromQuery] int? limit,
             [FromQuery] DateTime? minDate,
             [FromQuery] DateTime? minDate,
             [FromQuery] bool? hasUserId)
             [FromQuery] bool? hasUserId)
         {
         {
-            var filterFunc = new Func<IQueryable<ActivityLog>, IQueryable<ActivityLog>>(
-                entries => entries.Where(entry => entry.DateCreated >= minDate
-                                                  && (!hasUserId.HasValue || (hasUserId.Value
-                                                      ? entry.UserId != Guid.Empty
-                                                      : entry.UserId == Guid.Empty))));
-
-            return _activityManager.GetPagedResult(filterFunc, startIndex, limit);
+            return await _activityManager.GetPagedResultAsync(new ActivityLogQuery
+            {
+                StartIndex = startIndex,
+                Limit = limit,
+                MinDate = minDate,
+                HasUserId = hasUserId
+            }).ConfigureAwait(false);
         }
         }
     }
     }
 }
 }

+ 30 - 0
Jellyfin.Data/Queries/ActivityLogQuery.cs

@@ -0,0 +1,30 @@
+using System;
+
+namespace Jellyfin.Data.Queries
+{
+    /// <summary>
+    /// A class representing a query to the activity logs.
+    /// </summary>
+    public class ActivityLogQuery
+    {
+        /// <summary>
+        /// Gets or sets the index to start at.
+        /// </summary>
+        public int? StartIndex { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum number of items to include.
+        /// </summary>
+        public int? Limit { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether to take entries with a user id.
+        /// </summary>
+        public bool? HasUserId { get; set; }
+
+        /// <summary>
+        /// Gets or sets the minimum date to query for.
+        /// </summary>
+        public DateTime? MinDate { get; set; }
+    }
+}

+ 19 - 21
Jellyfin.Server.Implementations/Activity/ActivityManager.cs

@@ -3,8 +3,10 @@ using System.Linq;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Jellyfin.Data.Entities;
 using Jellyfin.Data.Entities;
 using Jellyfin.Data.Events;
 using Jellyfin.Data.Events;
+using Jellyfin.Data.Queries;
 using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
+using Microsoft.EntityFrameworkCore;
 
 
 namespace Jellyfin.Server.Implementations.Activity
 namespace Jellyfin.Server.Implementations.Activity
 {
 {
@@ -39,41 +41,37 @@ namespace Jellyfin.Server.Implementations.Activity
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
-        public QueryResult<ActivityLogEntry> GetPagedResult(
-            Func<IQueryable<ActivityLog>, IQueryable<ActivityLog>> func,
-            int? startIndex,
-            int? limit)
+        public async Task<QueryResult<ActivityLogEntry>> GetPagedResultAsync(ActivityLogQuery query)
         {
         {
-            using var dbContext = _provider.CreateContext();
+            await using var dbContext = _provider.CreateContext();
 
 
-            var query = func(dbContext.ActivityLogs.OrderByDescending(entry => entry.DateCreated));
+            IQueryable<ActivityLog> entries = dbContext.ActivityLogs
+                .AsQueryable()
+                .OrderByDescending(entry => entry.DateCreated);
 
 
-            if (startIndex.HasValue)
+            if (query.MinDate.HasValue)
             {
             {
-                query = query.Skip(startIndex.Value);
+                entries = entries.Where(entry => entry.DateCreated >= query.MinDate);
             }
             }
 
 
-            if (limit.HasValue)
+            if (query.HasUserId.HasValue)
             {
             {
-                query = query.Take(limit.Value);
+                entries = entries.Where(entry => entry.UserId != Guid.Empty == query.HasUserId.Value );
             }
             }
 
 
-            // This converts the objects from the new database model to the old for compatibility with the existing API.
-            var list = query.Select(ConvertToOldModel).ToList();
-
             return new QueryResult<ActivityLogEntry>
             return new QueryResult<ActivityLogEntry>
             {
             {
-                Items = list,
-                TotalRecordCount = func(dbContext.ActivityLogs).Count()
+                Items = await entries
+                    .Skip(query.StartIndex ?? 0)
+                    .Take(query.Limit ?? 100)
+                    .AsAsyncEnumerable()
+                    .Select(ConvertToOldModel)
+                    .ToListAsync()
+                    .ConfigureAwait(false),
+                TotalRecordCount = await entries.CountAsync().ConfigureAwait(false)
             };
             };
         }
         }
 
 
-        /// <inheritdoc/>
-        public QueryResult<ActivityLogEntry> GetPagedResult(int? startIndex, int? limit)
-        {
-            return GetPagedResult(logs => logs, startIndex, limit);
-        }
-
         private static ActivityLogEntry ConvertToOldModel(ActivityLog entry)
         private static ActivityLogEntry ConvertToOldModel(ActivityLog entry)
         {
         {
             return new ActivityLogEntry
             return new ActivityLogEntry

+ 1 - 0
Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj

@@ -24,6 +24,7 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
+    <PackageReference Include="System.Linq.Async" Version="4.1.1" />
     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.8">
     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.8">
       <PrivateAssets>all</PrivateAssets>
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

+ 1 - 0
Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs

@@ -61,6 +61,7 @@ namespace Jellyfin.Server.Implementations.Users
         public IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client)
         public IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client)
         {
         {
             return _dbContext.ItemDisplayPreferences
             return _dbContext.ItemDisplayPreferences
+                .AsQueryable()
                 .Where(prefs => prefs.UserId == userId && prefs.ItemId != Guid.Empty && string.Equals(prefs.Client, client))
                 .Where(prefs => prefs.UserId == userId && prefs.ItemId != Guid.Empty && string.Equals(prefs.Client, client))
                 .ToList();
                 .ToList();
         }
         }

+ 6 - 5
Jellyfin.Server.Implementations/Users/UserManager.cs

@@ -108,6 +108,7 @@ namespace Jellyfin.Server.Implementations.Users
             {
             {
                 using var dbContext = _dbProvider.CreateContext();
                 using var dbContext = _dbProvider.CreateContext();
                 return dbContext.Users
                 return dbContext.Users
+                    .AsQueryable()
                     .Select(user => user.Id)
                     .Select(user => user.Id)
                     .ToList();
                     .ToList();
             }
             }
@@ -200,8 +201,8 @@ namespace Jellyfin.Server.Implementations.Users
         internal async Task<User> CreateUserInternalAsync(string name, JellyfinDb dbContext)
         internal async Task<User> CreateUserInternalAsync(string name, JellyfinDb dbContext)
         {
         {
             // TODO: Remove after user item data is migrated.
             // TODO: Remove after user item data is migrated.
-            var max = await dbContext.Users.AnyAsync().ConfigureAwait(false)
-                ? await dbContext.Users.Select(u => u.InternalId).MaxAsync().ConfigureAwait(false)
+            var max = await dbContext.Users.AsQueryable().AnyAsync().ConfigureAwait(false)
+                ? await dbContext.Users.AsQueryable().Select(u => u.InternalId).MaxAsync().ConfigureAwait(false)
                 : 0;
                 : 0;
 
 
             return new User(
             return new User(
@@ -221,7 +222,7 @@ namespace Jellyfin.Server.Implementations.Users
                 throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)");
                 throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)");
             }
             }
 
 
-            using var dbContext = _dbProvider.CreateContext();
+            await using var dbContext = _dbProvider.CreateContext();
 
 
             var newUser = await CreateUserInternalAsync(name, dbContext).ConfigureAwait(false);
             var newUser = await CreateUserInternalAsync(name, dbContext).ConfigureAwait(false);
 
 
@@ -588,9 +589,9 @@ namespace Jellyfin.Server.Implementations.Users
         public async Task InitializeAsync()
         public async Task InitializeAsync()
         {
         {
             // TODO: Refactor the startup wizard so that it doesn't require a user to already exist.
             // TODO: Refactor the startup wizard so that it doesn't require a user to already exist.
-            using var dbContext = _dbProvider.CreateContext();
+            await using var dbContext = _dbProvider.CreateContext();
 
 
-            if (await dbContext.Users.AnyAsync().ConfigureAwait(false))
+            if (await dbContext.Users.AsQueryable().AnyAsync().ConfigureAwait(false))
             {
             {
                 return;
                 return;
             }
             }

+ 2 - 7
MediaBrowser.Model/Activity/IActivityManager.cs

@@ -1,10 +1,10 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
 
 
 using System;
 using System;
-using System.Linq;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Jellyfin.Data.Entities;
 using Jellyfin.Data.Entities;
 using Jellyfin.Data.Events;
 using Jellyfin.Data.Events;
+using Jellyfin.Data.Queries;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 
 
 namespace MediaBrowser.Model.Activity
 namespace MediaBrowser.Model.Activity
@@ -15,11 +15,6 @@ namespace MediaBrowser.Model.Activity
 
 
         Task CreateAsync(ActivityLog entry);
         Task CreateAsync(ActivityLog entry);
 
 
-        QueryResult<ActivityLogEntry> GetPagedResult(int? startIndex, int? limit);
-
-        QueryResult<ActivityLogEntry> GetPagedResult(
-            Func<IQueryable<ActivityLog>, IQueryable<ActivityLog>> func,
-            int? startIndex,
-            int? limit);
+        Task<QueryResult<ActivityLogEntry>> GetPagedResultAsync(ActivityLogQuery query);
     }
     }
 }
 }