Skip to content

Commit

Permalink
Support attributes on input parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
viceroypenguin committed Oct 12, 2024
1 parent fde50b9 commit 5098987
Show file tree
Hide file tree
Showing 10 changed files with 489 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ private sealed record Behavior
[ExcludeFromCodeCoverage]
private sealed record Parameter
{
public required string? Attributes { get; init; }
public required string Type { get; init; }
public required string Name { get; init; }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace Immediate.Handlers.Generators.ImmediateHandlers;

Expand Down Expand Up @@ -61,6 +62,7 @@ CancellationToken cancellationToken
.Take(handleMethod.Parameters.Length - (useToken ? 2 : 1))
.Select(p => new Parameter
{
Attributes = p.GetAttributesString(),
Type = p.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
Name = p.Name,
})
Expand Down Expand Up @@ -136,4 +138,44 @@ file static class Extensions
symbol
.GetAttributes()
.FirstOrDefault(a => a.AttributeClass.IsBehaviorsAttribute());

public static string? GetAttributesString(this IParameterSymbol parameter)
{
var attributes = parameter.GetAttributes();
if (attributes.Length == 0)
return null;

return $"[{string.Join(", ", attributes.Select(GetAttributeString))}] ";
}

private static string GetAttributeString(AttributeData attributeData)
{
var @class = attributeData.AttributeClass!.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

var parameters = new List<string>();

foreach (var tc in attributeData.ConstructorArguments)
{
if (tc.GetTypedConstantString() is { } str)
parameters.Add(str);
}

foreach (var na in attributeData.NamedArguments)
{
if (na.Value.GetTypedConstantString() is { } str)
parameters.Add($"{na.Key} = {str}");
}

return parameters.Count == 0
? @class
: $"{@class}({string.Join(", ", parameters)})";
}

[SuppressMessage("Style", "IDE0072:Add missing cases")]
private static string? GetTypedConstantString(this TypedConstant tc) =>
tc.Kind switch
{
TypedConstantKind.Array => $"[{string.Join(", ", tc.Values.Select(GetTypedConstantString))}]",
_ => tc.ToCSharpString(),
};
}
2 changes: 1 addition & 1 deletion src/Immediate.Handlers.Generators/Templates/Handler.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ partial class {{ class_name }}

public HandleBehavior(
{{~ for parameter in handler_parameters ~}}
{{ parameter.type }} {{ parameter.name }}{{ if !for.last }},{{ end }}
{{ parameter.attributes }}{{ parameter.type }} {{ parameter.name }}{{ if !for.last }},{{ end }}
{{~ end ~}}
)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//HintName: IH.Dummy.GetUsersQuery.g.cs
using Microsoft.Extensions.DependencyInjection;

#pragma warning disable CS1591

namespace Dummy;

partial class GetUsersQuery
{
public sealed partial class Handler : global::Immediate.Handlers.Shared.IHandler<global::Dummy.GetUsersQuery.Query, int>
{
private readonly global::Dummy.GetUsersQuery.HandleBehavior _handleBehavior;

public Handler(
global::Dummy.GetUsersQuery.HandleBehavior handleBehavior
)
{
var handlerType = typeof(GetUsersQuery);

_handleBehavior = handleBehavior;

}

public async global::System.Threading.Tasks.ValueTask<int> HandleAsync(
global::Dummy.GetUsersQuery.Query request,
global::System.Threading.CancellationToken cancellationToken = default
)
{
return await _handleBehavior
.HandleAsync(request, cancellationToken)
.ConfigureAwait(false);
}
}

[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public sealed class HandleBehavior : global::Immediate.Handlers.Shared.Behavior<global::Dummy.GetUsersQuery.Query, int>
{
private readonly global::Dummy.Service _service;

public HandleBehavior(
[global::Dummy.TestAttribute(["Dummy1", "Dummy2"], ["Dummy1", "Dummy2"], ["Dummy3", "Dummy4"])] global::Dummy.Service service
)
{
_service = service;
}

public override async global::System.Threading.Tasks.ValueTask<int> HandleAsync(
global::Dummy.GetUsersQuery.Query request,
global::System.Threading.CancellationToken cancellationToken
)
{
return await global::Dummy.GetUsersQuery
.HandleAsync(
request
, _service
, cancellationToken
)
.ConfigureAwait(false);
}
}

[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public static IServiceCollection AddHandlers(
IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped
)
{
services.Add(new(typeof(global::Dummy.GetUsersQuery.Handler), typeof(global::Dummy.GetUsersQuery.Handler), lifetime));
services.Add(new(typeof(global::Immediate.Handlers.Shared.IHandler<global::Dummy.GetUsersQuery.Query, int>), typeof(global::Dummy.GetUsersQuery.Handler), lifetime));
services.Add(new(typeof(global::Dummy.GetUsersQuery.HandleBehavior), typeof(global::Dummy.GetUsersQuery.HandleBehavior), lifetime));
return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//HintName: IH.ServiceCollectionExtensions.g.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

#pragma warning disable CS1591

public static class HandlerServiceCollectionExtensions
{
public static IServiceCollection AddBehaviors(
this IServiceCollection services)
{

return services;
}

public static IServiceCollection AddHandlers(
this IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped
)
{
global::Dummy.GetUsersQuery.AddHandlers(services, lifetime);

return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//HintName: IH.Dummy.GetUsersQuery.g.cs
using Microsoft.Extensions.DependencyInjection;

#pragma warning disable CS1591

namespace Dummy;

partial class GetUsersQuery
{
public sealed partial class Handler : global::Immediate.Handlers.Shared.IHandler<global::Dummy.GetUsersQuery.Query, int>
{
private readonly global::Dummy.GetUsersQuery.HandleBehavior _handleBehavior;

public Handler(
global::Dummy.GetUsersQuery.HandleBehavior handleBehavior
)
{
var handlerType = typeof(GetUsersQuery);

_handleBehavior = handleBehavior;

}

public async global::System.Threading.Tasks.ValueTask<int> HandleAsync(
global::Dummy.GetUsersQuery.Query request,
global::System.Threading.CancellationToken cancellationToken = default
)
{
return await _handleBehavior
.HandleAsync(request, cancellationToken)
.ConfigureAwait(false);
}
}

[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public sealed class HandleBehavior : global::Immediate.Handlers.Shared.Behavior<global::Dummy.GetUsersQuery.Query, int>
{
private readonly global::Dummy.SomeKeyedService _service;

public HandleBehavior(
[global::Microsoft.Extensions.DependencyInjection.FromKeyedServicesAttribute("SomeServiceKey"), global::Dummy.TestAttribute(Message = "Test")] global::Dummy.SomeKeyedService service
)
{
_service = service;
}

public override async global::System.Threading.Tasks.ValueTask<int> HandleAsync(
global::Dummy.GetUsersQuery.Query request,
global::System.Threading.CancellationToken cancellationToken
)
{
return await global::Dummy.GetUsersQuery
.HandleAsync(
request
, _service
, cancellationToken
)
.ConfigureAwait(false);
}
}

[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public static IServiceCollection AddHandlers(
IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped
)
{
services.Add(new(typeof(global::Dummy.GetUsersQuery.Handler), typeof(global::Dummy.GetUsersQuery.Handler), lifetime));
services.Add(new(typeof(global::Immediate.Handlers.Shared.IHandler<global::Dummy.GetUsersQuery.Query, int>), typeof(global::Dummy.GetUsersQuery.Handler), lifetime));
services.Add(new(typeof(global::Dummy.GetUsersQuery.HandleBehavior), typeof(global::Dummy.GetUsersQuery.HandleBehavior), lifetime));
return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//HintName: IH.ServiceCollectionExtensions.g.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

#pragma warning disable CS1591

public static class HandlerServiceCollectionExtensions
{
public static IServiceCollection AddBehaviors(
this IServiceCollection services)
{

return services;
}

public static IServiceCollection AddHandlers(
this IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped
)
{
global::Dummy.GetUsersQuery.AddHandlers(services, lifetime);

return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//HintName: IH.Dummy.GetUsersQuery.g.cs
using Microsoft.Extensions.DependencyInjection;

#pragma warning disable CS1591

namespace Dummy;

partial class GetUsersQuery
{
public sealed partial class Handler : global::Immediate.Handlers.Shared.IHandler<global::Dummy.GetUsersQuery.Query, int>
{
private readonly global::Dummy.GetUsersQuery.HandleBehavior _handleBehavior;

public Handler(
global::Dummy.GetUsersQuery.HandleBehavior handleBehavior
)
{
var handlerType = typeof(GetUsersQuery);

_handleBehavior = handleBehavior;

}

public async global::System.Threading.Tasks.ValueTask<int> HandleAsync(
global::Dummy.GetUsersQuery.Query request,
global::System.Threading.CancellationToken cancellationToken = default
)
{
return await _handleBehavior
.HandleAsync(request, cancellationToken)
.ConfigureAwait(false);
}
}

[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public sealed class HandleBehavior : global::Immediate.Handlers.Shared.Behavior<global::Dummy.GetUsersQuery.Query, int>
{
private readonly global::Dummy.SomeKeyedService _service;

public HandleBehavior(
[global::Microsoft.Extensions.DependencyInjection.FromKeyedServicesAttribute("SomeServiceKey")] global::Dummy.SomeKeyedService service
)
{
_service = service;
}

public override async global::System.Threading.Tasks.ValueTask<int> HandleAsync(
global::Dummy.GetUsersQuery.Query request,
global::System.Threading.CancellationToken cancellationToken
)
{
return await global::Dummy.GetUsersQuery
.HandleAsync(
request
, _service
, cancellationToken
)
.ConfigureAwait(false);
}
}

[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public static IServiceCollection AddHandlers(
IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped
)
{
services.Add(new(typeof(global::Dummy.GetUsersQuery.Handler), typeof(global::Dummy.GetUsersQuery.Handler), lifetime));
services.Add(new(typeof(global::Immediate.Handlers.Shared.IHandler<global::Dummy.GetUsersQuery.Query, int>), typeof(global::Dummy.GetUsersQuery.Handler), lifetime));
services.Add(new(typeof(global::Dummy.GetUsersQuery.HandleBehavior), typeof(global::Dummy.GetUsersQuery.HandleBehavior), lifetime));
return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//HintName: IH.ServiceCollectionExtensions.g.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

#pragma warning disable CS1591

public static class HandlerServiceCollectionExtensions
{
public static IServiceCollection AddBehaviors(
this IServiceCollection services)
{

return services;
}

public static IServiceCollection AddHandlers(
this IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped
)
{
global::Dummy.GetUsersQuery.AddHandlers(services, lifetime);

return services;
}
}
Loading

0 comments on commit 5098987

Please sign in to comment.