Files
pgsql-jellyfin/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs
wjones f833f0ceeb BaseItemRepository: 100% async conversion complete
All 21 public methods in BaseItemRepository are now fully async, including complex query, retrieval, write, delete, and aggregation operations. Added async signatures to IItemRepository and ILibraryManager with cancellation token support and ConfigureAwait(false). Sync wrappers retained for backward compatibility. Final conversion of GetLatestItemList and GetNextUpSeriesKeys completes Phase 3A. All bulk operations and aggregations are async, enabling concurrent dashboard loading and full PostgreSQL multiplexing. Migration routines fixed for Npgsql "command in progress" errors. Extensive documentation added for conversion process, performance, and testing. Project is now production-ready with zero build errors and 100% backward compatibility.
2026-02-23 12:36:29 -05:00

77 lines
3.0 KiB
C#

// <copyright file="MigrateRatingLevels.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace Jellyfin.Server.Migrations.Routines;
using System;
using System.Linq;
using Jellyfin.Database.Implementations;
using Jellyfin.Server.ServerSetupApp;
using MediaBrowser.Model.Globalization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
/// <summary>
/// Migrate rating levels.
/// </summary>
#pragma warning disable CS0618 // Type or member is obsolete
[JellyfinMigration("2025-04-20T22:00:00", nameof(MigrateRatingLevels))]
[JellyfinMigrationBackup(JellyfinDb = true)]
#pragma warning restore CS0618 // Type or member is obsolete
internal class MigrateRatingLevels : IDatabaseMigrationRoutine
{
private readonly IStartupLogger _logger;
private readonly IDbContextFactory<JellyfinDbContext> _provider;
private readonly ILocalizationManager _localizationManager;
public MigrateRatingLevels(
IDbContextFactory<JellyfinDbContext> provider,
IStartupLogger<MigrateRatingLevels> logger,
ILocalizationManager localizationManager)
{
_provider = provider;
_localizationManager = localizationManager;
_logger = logger;
}
/// <inheritdoc/>
public void Perform()
{
_logger.LogInformation("Recalculating parental rating levels based on rating string.");
using var context = _provider.CreateDbContext();
using var transaction = context.Database.BeginTransaction();
// Materialize the ratings list first to avoid "command in progress" error
var ratings = context.BaseItems.AsNoTracking().Select(e => e.OfficialRating).Distinct().ToList();
foreach (var rating in ratings)
{
if (string.IsNullOrEmpty(rating))
{
int? value = null;
context.BaseItems
.Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty)
.ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingValue, value));
context.BaseItems
.Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty)
.ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingSubValue, value));
}
else
{
var ratingValue = _localizationManager.GetRatingScore(rating);
var score = ratingValue?.Score;
var subScore = ratingValue?.SubScore;
context.BaseItems
.Where(e => e.OfficialRating == rating)
.ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingValue, score));
context.BaseItems
.Where(e => e.OfficialRating == rating)
.ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingSubValue, subScore));
}
}
transaction.Commit();
}
}