< Summary

Line coverage
91%
Covered lines: 103
Uncovered lines: 9
Coverable lines: 112
Total lines: 266
Line coverage: 91.9%
Branch coverage
100%
Covered branches: 4
Total branches: 4
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: Initialize(...)100%22100%
File 1: .ctor(...)100%11100%
File 1: CreateParameterDescriptor_UpdateWorkAsync_input()100%11100%
File 1: UpdateWorkAsync()100%11100%
File 1: UpdateWorkAsync()100%210%
File 2: UpdateWorkAsync()100%11100%

File(s)

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/obj/Debug/net10.0/generated/HotChocolate.Types.Analyzers/HotChocolate.Types.Analyzers.GraphQLServerGenerator/UpdateWorkMutations.5K_PEMQ_7wff-4-lE1HACg.hc.g.cs

#LineLine coverage
 1// <auto-generated/>
 2
 3#nullable enable
 4#pragma warning disable
 5
 6using System;
 7using System.Runtime.CompilerServices;
 8using HotChocolate;
 9using HotChocolate.Types;
 10using HotChocolate.Execution.Configuration;
 11using Microsoft.Extensions.DependencyInjection;
 12using HotChocolate.Internal;
 13
 14namespace Api.Works.Mutations
 15{
 16    public static partial class UpdateWorkMutations
 17    {
 18        internal static void Initialize(global::HotChocolate.Types.IObjectTypeDescriptor descriptor)
 119        {
 120            var extension = descriptor.Extend();
 121            var configuration = extension.Configuration;
 122            var thisType = typeof(global::Api.Works.Mutations.UpdateWorkMutations);
 123            var bindingResolver = extension.Context.ParameterBindingResolver;
 124            var resolvers = new __Resolvers(bindingResolver);
 25
 126            HotChocolate.Internal.ConfigurationHelper.ApplyConfiguration(
 127                extension.Context,
 128                descriptor,
 129                typeof(global::Api.Works.Mutations.UpdateWorkMutations),
 130                new global::HotChocolate.Types.MutationTypeAttribute());
 131            configuration.ConfigurationsAreApplied = true;
 32
 133            var naming = descriptor.Extend().Context.Naming;
 34
 135            descriptor
 136                .Field(naming.GetMemberName("UpdateWork", global::HotChocolate.Types.MemberKind.ObjectField))
 137                .ExtendWith(static (field, context) =>
 138                {
 139                    var configuration = field.Configuration;
 140                    var typeInspector = field.Context.TypeInspector;
 141                    var bindingResolver = field.Context.ParameterBindingResolver;
 142                    var naming = field.Context.Naming;
 143
 144                    configuration.Type = global::HotChocolate.Types.Descriptors.TypeReference.Create(
 145                        typeInspector.GetTypeRef(typeof(global::Api.Works.Mutations.UpdateWorkPayload), HotChocolate.Typ
 146                        new global::HotChocolate.Language.NonNullTypeNode(new global::HotChocolate.Language.NamedTypeNod
 147                    configuration.ResultType = typeof(global::Api.Works.Mutations.UpdateWorkPayload);
 148                    configuration.DeclaringType = context.ThisType;
 149
 150                    configuration.SetSourceGeneratorFlags();
 151
 152                    var bindingInfo = field.Context.ParameterBindingResolver;
 153                    var parameter = context.Resolvers.CreateParameterDescriptor_UpdateWorkAsync_input();
 154                    var parameterInfo = bindingInfo.GetBindingInfo(parameter);
 155
 156                    if(parameterInfo.Kind is global::HotChocolate.Internal.ArgumentKind.Argument)
 157                    {
 158                        var argumentConfiguration = new global::HotChocolate.Types.Descriptors.Configurations.ArgumentCo
 159                        {
 160                            Name = naming.GetMemberName("input", global::HotChocolate.Types.MemberKind.Argument),
 161                            Type = global::HotChocolate.Types.Descriptors.TypeReference.Create(
 162                                typeInspector.GetTypeRef(typeof(global::Api.Works.Mutations.UpdateWorkInput), HotChocola
 163                                new global::HotChocolate.Language.NonNullTypeNode(new global::HotChocolate.Language.Name
 164                            RuntimeType = typeof(global::Api.Works.Mutations.UpdateWorkInput)
 165                        };
 166
 167                        configuration.Arguments.Add(argumentConfiguration);
 168                    }
 169
 170                    configuration.Member = context.ThisType.GetMethod(
 171                        "UpdateWorkAsync",
 172                        global::HotChocolate.Utilities.ReflectionUtils.StaticMemberFlags,
 173                        new global::System.Type[]
 174                        {
 175                            typeof(global::Api.Database.PGContext),
 176                            typeof(global::Api.Database.Utils.IEFTransactionDIAccessorService),
 177                            typeof(global::FluentValidation.IValidator<global::Api.Works.Mutations.UpdateWorkInput>),
 178                            typeof(global::Api.Works.Mutations.UpdateWorkInput),
 179                            typeof(global::System.Threading.CancellationToken)
 180                        })!;
 181
 182                    var fieldDescriptor = global::HotChocolate.Types.Descriptors.ObjectFieldDescriptor.From(field.Contex
 183                    HotChocolate.Internal.ConfigurationHelper.ApplyConfiguration(
 184                        field.Context,
 185                        fieldDescriptor,
 186                        configuration.Member,
 187                        new global::Api.Auth.Handlers.PermissionCheckAuthorizeAttribute((global::Api.Auth.Models.UserPer
 188                        new global::HotChocolate.Types.ErrorAttribute(typeof(global::Api.Utils.DomainError)));
 189
 190                    bindingResolver.ApplyConfiguration(
 191                        context.Resolvers.CreateParameterDescriptor_UpdateWorkAsync_input(),
 192                        fieldDescriptor);
 193
 194                    configuration.ConfigurationsAreApplied = true;
 195                    fieldDescriptor.CreateConfiguration();
 196
 197                    configuration.Resolvers = context.Resolvers.UpdateWorkAsync();
 198                },
 199                (Resolvers: resolvers, ThisType: thisType));
 100
 101            Configure(descriptor);
 1102        }
 103
 104        static partial void Configure(global::HotChocolate.Types.IObjectTypeDescriptor descriptor);
 105
 106        private sealed class __Resolvers
 107        {
 108            private readonly global::HotChocolate.Internal.IParameterBinding _binding_UpdateWorkAsync_input;
 109
 1110            public __Resolvers(global::HotChocolate.Resolvers.ParameterBindingResolver bindingResolver)
 1111            {
 1112                _binding_UpdateWorkAsync_input = bindingResolver.GetBinding(CreateParameterDescriptor_UpdateWorkAsync_in
 1113            }
 114
 115            public global::HotChocolate.Internal.ParameterDescriptor CreateParameterDescriptor_UpdateWorkAsync_input()
 1116                => new HotChocolate.Internal.ParameterDescriptor(
 1117                    "input",
 1118                    typeof(global::Api.Works.Mutations.UpdateWorkInput),
 1119                    isNullable: false,
 1120                    []);
 121
 122            public HotChocolate.Resolvers.FieldResolverDelegates UpdateWorkAsync()
 1123                => new global::HotChocolate.Resolvers.FieldResolverDelegates(resolver: UpdateWorkAsync);
 124
 125            private async global::System.Threading.Tasks.ValueTask<global::System.Object?> UpdateWorkAsync(global::HotCh
 0126            {
 0127                var args0 = context.Service<global::Api.Database.PGContext>();
 0128                var args1 = context.Service<global::Api.Database.Utils.IEFTransactionDIAccessorService>();
 0129                var args2 = context.Service<global::FluentValidation.IValidator<global::Api.Works.Mutations.UpdateWorkIn
 0130                var args3 = _binding_UpdateWorkAsync_input.Execute<global::Api.Works.Mutations.UpdateWorkInput>(context)
 0131                var args4 = context.RequestAborted;
 0132                var result = await global::Api.Works.Mutations.UpdateWorkMutations.UpdateWorkAsync(args0, args1, args2, 
 0133                return result;
 0134            }
 135        }
 136    }
 137}
 138

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

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <alper@alper-celik.dev>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5using Api.Auth.Handlers;
 6using Api.Auth.Models;
 7using Api.Auth.Utils;
 8using Api.Database;
 9using Api.Database.Utils;
 10using Api.Utils;
 11using Api.Works.Models;
 12using Api.Works.Queries;
 13using FluentValidation;
 14using Microsoft.EntityFrameworkCore;
 15using NodaTime;
 16
 17namespace Api.Works.Mutations;
 18
 19[MutationType]
 20public static partial class UpdateWorkMutations
 21{
 22    [PermissionCheckAuthorize(UserPermissionBits.WorkRead | UserPermissionBits.WorkWrite)]
 23    [Error(typeof(DomainError))]
 24    public static async Task<UpdateWorkPayload> UpdateWorkAsync(
 25        [Service] PGContext db,
 26        [Service] IEFTransactionDIAccessorService txGetter,
 27        [Service] IValidator<UpdateWorkInput> validator,
 28        UpdateWorkInput input,
 29        CancellationToken ct
 30    )
 131    {
 132        await validator.ValidateOrThrowInputAsync(input, ct);
 33
 134        var tx = await txGetter.BeginOrGetTransactionAsync();
 135        var work = await db
 136            .Works.Include(w => w.WorkTag_Works)
 137            .Include(w => w.Work_Authors)
 138            .SingleAsync(w => w.Id == input.Id, cancellationToken: ct);
 39
 140        UpdateWorkInput.ApplyToWork(work, input);
 141        work.RowVersion += 1;
 142        work.MetadataUpdatedAt = Now();
 43
 144        await db.SaveChangesAsync(cancellationToken: ct);
 45
 146        await tx.CommitAsync(ct);
 147        return new UpdateWorkPayload(WorkMapper.ToDto(work));
 148    }
 49}
 50
 51public record UpdateWorkPayload(Queries.Work Work);
 52
 53public record UpdateWorkInput : IBasicEntityMetadata
 54{
 55    public static byte IdPostfix => Models.Work.IdPostfix;
 56
 57    public Guid Id { get; init; }
 58    public int RowVersion { get; init; }
 59
 60    public Optional<string> Title { get; init; }
 61    public Optional<string?> Description { get; init; }
 62
 63    public Optional<Instant?> WorkPublishedAt { get; init; }
 64    public Optional<Instant?> WorkUpdatedAt { get; init; }
 65    public Optional<List<Queries.WorkIdentifier>?> WorkIdentifiers { get; init; }
 66    public required Optional<List<Guid>?> TagIds { get; init; }
 67    public required Optional<List<Guid>?> AuthorIds { get; init; }
 68
 69    public class UpdateWorkInputValidator : AbstractValidator<UpdateWorkInput>
 70    {
 71        public UpdateWorkInputValidator(
 72            PGContext db,
 73            ICurrentUserId userId,
 74            IEFTransactionDIAccessorService tx
 75        )
 76        {
 77            RuleFor(w => w).BeginTransaction(tx);
 78
 79            RuleFor(w => w.Id).IdMustExist(db.Works, userId.Id);
 80
 81            RuleFor(w => w.RowVersion).RowVersionMustMatch(db.Works);
 82
 83            RuleFor(w => w.TagIds.Value!)
 84                .MustBeDistinct(nameof(TagIds))
 85                .WhenOptionalSet(w => w.TagIds);
 86            RuleFor(w => w.TagIds.Value!)
 87                .IdsMustExist(db.WorkTags, userId.Id)
 88                .WhenOptionalSet(w => w.TagIds);
 89
 90            RuleFor(w => w.AuthorIds.Value!)
 91                .MustBeDistinct(nameof(AuthorIds))
 92                .WhenOptionalSet(w => w.AuthorIds);
 93            RuleFor(w => w.AuthorIds.Value!)
 94                .IdsMustExist(db.Authors, userId.Id)
 95                .WhenOptionalSet(w => w.AuthorIds);
 96        }
 97    }
 98
 99    public static void ApplyToWork(Models.Work work, UpdateWorkInput input)
 100    {
 101        if (input.Title.HasValue)
 102            work.Title = input.Title.Value;
 103
 104        if (input.Description.HasValue)
 105            work.Description = input.Description.Value;
 106
 107        if (input.WorkPublishedAt.HasValue)
 108            work.WorkPublishedAt = input.WorkPublishedAt.Value?.InUtc();
 109
 110        if (input.WorkUpdatedAt.HasValue)
 111            work.WorkUpdatedAt = input.WorkUpdatedAt.Value?.InUtc();
 112
 113        if (input.WorkIdentifiers.HasValue)
 114            work.WorkIdentifiers =
 115                input.WorkIdentifiers.Value?.Select(WorkMapper.FromWorkIdDto).ToList()
 116                ?? [];
 117
 118        if (input.TagIds.HasValue)
 119            work.WorkTag_Works =
 120                input.TagIds.Value?.Select(t => new WorkTag_Work(work.Id, t)).ToList()
 121                ?? [];
 122
 123        if (input.AuthorIds.HasValue)
 124            work.Work_Authors =
 125                input.AuthorIds.Value?.Select(t => new Work_Author(work.Id, t)).ToList()
 126                ?? [];
 127    }
 128}