From 6dac2d724c802ac7e7529162a970942e0c5ef43a Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 9 Jul 2026 19:53:29 +0200 Subject: [PATCH] =?UTF-8?q?fix(#193):=20review=20follow-ups=20=E2=80=94=20?= =?UTF-8?q?drop=20Playlist=20option,=20non-tracking=20existence=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adversarial review follow-ups on the #193 rerun selection validation: - RerunCollectionEditor.razor: remove the CollectionType.Playlist dropdown option — RerunCollection has no PlaylistId column, so the option previously persisted a broken row and now fails validation. - RerunCollectionSelectionValidation: replace FindAsync with a non-tracking AnyAsync(EF.Property("Id") == id) existence check so nothing is materialized/tracked into the save-path context. - Tests: pin the deliberate 422-not-404 choice (ShouldNotBeOfType) and cover the unsupported-type default arm (Playlist -> "Unsupported collection type"), which was reachable via the Blazor editor. Co-Authored-By: Claude Fable 5 --- .../RerunCollectionSelectionValidation.cs | 4 +++- .../RerunCollectionHandlerTests.cs | 17 +++++++++++++++++ ErsatzTV/Pages/RerunCollectionEditor.razor | 1 - 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ErsatzTV.Application/MediaCollections/Commands/RerunCollectionSelectionValidation.cs b/ErsatzTV.Application/MediaCollections/Commands/RerunCollectionSelectionValidation.cs index 6eced314f..ba3764ed9 100644 --- a/ErsatzTV.Application/MediaCollections/Commands/RerunCollectionSelectionValidation.cs +++ b/ErsatzTV.Application/MediaCollections/Commands/RerunCollectionSelectionValidation.cs @@ -100,7 +100,9 @@ internal static class RerunCollectionSelectionValidation CancellationToken cancellationToken) where T : class { - if (id is null || await set.FindAsync([id.Value], cancellationToken) is null) + // pure existence check — no tracking, nothing materialized into the save-path context + if (id is null || + !await set.AnyAsync(e => EF.Property(e, "Id") == id.Value, cancellationToken)) { return Fail(errorMessage); } diff --git a/ErsatzTV.Tests/Application/MediaCollections/RerunCollectionHandlerTests.cs b/ErsatzTV.Tests/Application/MediaCollections/RerunCollectionHandlerTests.cs index 49326853b..b1998754d 100644 --- a/ErsatzTV.Tests/Application/MediaCollections/RerunCollectionHandlerTests.cs +++ b/ErsatzTV.Tests/Application/MediaCollections/RerunCollectionHandlerTests.cs @@ -3,6 +3,7 @@ using ErsatzTV.Application.MediaCollections; using ErsatzTV.Application.MediaItems; using ErsatzTV.Core; using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Errors; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Tests.Support; @@ -32,9 +33,25 @@ public class RerunCollectionHandlerTests : MediaCollectionHandlerTestBase CancellationToken.None); BaseError error = LeftOf(result); + // deliberate 422-not-404: the missing entity is a request-body FK, not the route resource + error.ShouldNotBeOfType(); error.Value.ShouldContain("Collection does not exist"); } + [Test] + public async Task Create_Should_Return_Error_When_CollectionType_Unsupported() + { + var handler = new CreateRerunCollectionHandler(Db.Factory); + + // reachable via the legacy Blazor editor (no IsSupportedSelectionType pre-check) + Either result = await handler.Handle( + MakeCreate(CollectionType.Playlist), + CancellationToken.None); + + BaseError error = LeftOf(result); + error.Value.ShouldContain("Unsupported collection type"); + } + [Test] public async Task Create_Should_Return_Error_When_MediaItem_Missing() { diff --git a/ErsatzTV/Pages/RerunCollectionEditor.razor b/ErsatzTV/Pages/RerunCollectionEditor.razor index 55de44f0f..62ed65e95 100644 --- a/ErsatzTV/Pages/RerunCollectionEditor.razor +++ b/ErsatzTV/Pages/RerunCollectionEditor.razor @@ -36,7 +36,6 @@ Artist Multi Collection Smart Collection - Playlist @if (_model.CollectionType == CollectionType.Collection)