< Summary

Information
Class: Api.Works.Mutations.UpdateAuthorInput
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Works/Mutations/UpdateAuthorMutation.cs
Line coverage
95%
Covered lines: 20
Uncovered lines: 1
Coverable lines: 21
Total lines: 97
Line coverage: 95.2%
Branch coverage
90%
Covered branches: 9
Total branches: 10
Branch coverage: 90%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_IdPostfix()100%210%
.ctor(...)100%11100%
ApplyToAuthor(...)90%1010100%

File(s)

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Works/Mutations/UpdateAuthorMutation.cs

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <[email protected]>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5// Mostly Ai Generated - Start
 6using Api.Auth.Handlers;
 7using Api.Auth.Models;
 8using Api.Auth.Utils;
 9using Api.Database;
 10using Api.Database.Utils;
 11using Api.Utils;
 12using Api.Works.Queries;
 13using FluentValidation;
 14using Microsoft.EntityFrameworkCore;
 15
 16namespace Api.Works.Mutations;
 17
 18[MutationType]
 19public static partial class UpdateAuthorMutations
 20{
 21    [PermissionCheckAuthorize(
 22        UserPermissionBits.AuthorRead | UserPermissionBits.AuthorWrite
 23    )]
 24    [Error(typeof(DomainError))]
 25    public static async Task<UpdateAuthorPayload> UpdateAuthorAsync(
 26        [Service] PGContext db,
 27        [Service] IEFTransactionDIAccessorService txGetter,
 28        [Service] IValidator<UpdateAuthorInput> validator,
 29        UpdateAuthorInput input,
 30        CancellationToken ct
 31    )
 32    {
 33        await validator.ValidateOrThrowInputAsync(input, ct);
 34
 35        var tx = await txGetter.BeginOrGetTransactionAsync();
 36        var author = await db.Authors.SingleAsync(
 37            a => a.Id == input.Id,
 38            cancellationToken: ct
 39        );
 40
 41        UpdateAuthorInput.ApplyToAuthor(author, input);
 42        author.RowVersion += 1;
 43        author.MetadataUpdatedAt = Now();
 44
 45        await db.SaveChangesAsync(cancellationToken: ct);
 46
 47        await tx.CommitAsync(ct);
 48        return new UpdateAuthorPayload(AuthorMapper.ToDto(author));
 49    }
 50}
 51
 52public record UpdateAuthorPayload(Queries.Author Author);
 53
 54public record UpdateAuthorInput : IBasicEntityMetadata
 55{
 056    public static byte IdPostfix => Models.Author.IdPostfix;
 57
 58    public Guid Id { get; init; }
 59    public int RowVersion { get; init; }
 60
 61    public Optional<string?> FirstName { get; init; }
 62    public Optional<string?> LastName { get; init; }
 63    public required Optional<string> DisplayName { get; init; }
 64    public required Optional<List<string>?> PenNames { get; init; }
 65
 66    public class UpdateAuthorInputValidator : AbstractValidator<UpdateAuthorInput>
 67    {
 168        public UpdateAuthorInputValidator(
 169            PGContext db,
 170            ICurrentUserId userId,
 171            IEFTransactionDIAccessorService tx
 172        )
 173        {
 174            RuleFor(a => a).BeginTransaction(tx);
 75
 176            RuleFor(w => w.Id).IdMustExist(db.Authors, userId.Id);
 77
 178            RuleFor(w => w.RowVersion).RowVersionMustMatch(db.Authors);
 179        }
 80    }
 81
 82    public static void ApplyToAuthor(Models.Author author, UpdateAuthorInput input)
 183    {
 184        if (input.FirstName.HasValue)
 185            author.FirstName = input.FirstName.Value;
 86
 187        if (input.LastName.HasValue)
 188            author.LastName = input.LastName.Value;
 89
 190        if (input.DisplayName.HasValue)
 191            author.DisplayName = input.DisplayName.Value;
 92
 193        if (input.PenNames.HasValue)
 194            author.PenNames = input.PenNames.Value ?? [];
 195    }
 96}
 97// Mostly Ai Generated - End