Skip to content

Commit

Permalink
add using rich transients as parameters test case
Browse files Browse the repository at this point in the history
- add lookup transients by id conventions
  • Loading branch information
dncsvr committed Oct 28, 2024
1 parent ccd58ce commit 1b8ee83
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Baked.Business;
using Baked.Domain.Model;
using Baked.RestApi.Configuration;

namespace Baked.CodingStyle.RichTransient;

public class LookUpTransientByIdConvention(DomainModel _domain)
: IApiModelConvention<ParameterModelContext>
{
public void Apply(ParameterModelContext context)
{
if (context.Action.MappedMethod is null) { return; }
if (context.Action.MappedMethod.Has<InitializerAttribute>()) { return; }
if (!context.Parameter.IsInvokeMethodParameter) { return; }
if (context.Parameter.MappedParameter is null) { return; }
if (!context.Parameter.MappedParameter.ParameterType.TryGetMembers(out var members)) { return; }
if (!members.Has<LocatableAttribute>()) { return; }
if (members.TryGetQueryType(_domain, out var _)) { return; }

var initializer = members.Methods.Having<InitializerAttribute>().Single();
if (!initializer.DefaultOverload.Parameters.TryGetValue("id", out var parameter)) { return; }

var factoryParameter = context.Action.AddFactoryAsService(_domain, context.Parameter.MappedParameter.ParameterType);
context.Parameter.Name = $"{context.Parameter.Name}Id";
context.Parameter.Type = "string";
context.Parameter.LookupRenderer = p => factoryParameter.BuildInitializer(p);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Baked.Business;
using Baked.Domain.Model;
using Baked.RestApi.Configuration;
using Humanizer;

namespace Baked.CodingStyle.RichTransient;

public class LookUpTransientsByIdsConvention(DomainModel _domain)
: IApiModelConvention<ParameterModelContext>
{
public void Apply(ParameterModelContext context)
{
if (context.Action.MappedMethod is null) { return; }
if (context.Action.MappedMethod.Has<InitializerAttribute>()) { return; }
if (!context.Parameter.IsInvokeMethodParameter) { return; }
if (context.Parameter.MappedParameter is null) { return; }
if (!context.Parameter.MappedParameter.ParameterType.TryGetElementType(out var elementType)) { return; }
if (elementType.TryGetQueryContextType(_domain, out var queryContextType)) { return; }
if (!elementType.GetMetadata().Has<LocatableAttribute>()) { return; }

var initializer = elementType.GetMembers().Methods.Having<InitializerAttribute>().Single();
if (!initializer.DefaultOverload.Parameters.TryGetValue("id", out var parameter)) { return; }

var factoryParameter = context.Action.AddFactoryAsService(_domain, elementType);

context.Parameter.Type = "IEnumerable<string>";
context.Parameter.Name = $"{context.Parameter.Name.Singularize()}Ids";
context.Parameter.LookupRenderer = p => factoryParameter.BuildInitializerByIds(p, isArray: context.Parameter.TypeModel.IsArray);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,52 @@
using Baked.CodingStyle;
using Baked.Business;
using Baked.CodingStyle;
using Baked.CodingStyle.RichTransient;
using Baked.Domain.Model;
using Baked.RestApi.Model;
using Humanizer;
using ParameterModel = Baked.RestApi.Model.ParameterModel;

namespace Baked;

public static class RichTransientCodingStyleExtensions
{
public static RichTransientCodingStyleFeature RichTransient(this CodingStyleConfigurator _) =>
new();

public static ParameterModel AddFactoryAsService(this ActionModel action, DomainModel domain, TypeModel transientType)

Check failure on line 16 in src/recipe/Baked.Recipe.Service.Application/CodingStyle/RichTransient/RichTransientCodingStyleExtensions.cs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest)

Remove unused parameter 'domain' if it is not part of a shipped public API
{
var parameter =
new ParameterModel(transientType, ParameterModelFrom.Services, $"new{transientType.Name.Pascalize()}")
{
IsInvokeMethodParameter = false,
Type = $"Func<{transientType.CSharpFriendlyFullName}>"
};

action.Parameter[parameter.Name] = parameter;

return parameter;
}

public static string BuildInitializer(this ParameterModel factoryParameter, string valueExpression)
{
if (factoryParameter.TypeModel is null) { throw new("FactoryParameter shold have mapped parameter"); }

var initializer = factoryParameter.TypeModel.GetMembers().Methods.Having<InitializerAttribute>().Single();

return $"new{factoryParameter.TypeModel.Name.Pascalize()}().{initializer.Name}({valueExpression})";
}

public static string BuildInitializerByIds(this ParameterModel factoryParameter, string valueExpression,
bool isArray = default
)
{
if (factoryParameter.TypeModel is null) { throw new("FactoryParameter shold have mapped parameter"); }

var initializer = factoryParameter.TypeModel.GetMembers().Methods.Having<InitializerAttribute>().Single();
var byIds = $"{valueExpression}.Select(id => new{factoryParameter.TypeModel.Name.Pascalize()}().{initializer.Name}(id))";

return isArray
? $"{byIds}.ToArray()"
: $"{byIds}.ToList()";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public void Configure(LayerConfigurator configurator)
when: c =>
c.Type.IsClass && !c.Type.IsAbstract &&
c.Type.TryGetMembers(out var members) &&
members.Has<TransientAttribute>() &&
members.Has<ServiceAttribute>() &&
members.Has<TransientAttribute>() &&
members.Methods.Any(m =>
m.Has<InitializerAttribute>() &&
m.DefaultOverload.IsPublic &&
Expand All @@ -30,7 +30,7 @@ public void Configure(LayerConfigurator configurator)
(p.ParameterType.IsValueType || p.ParameterType.Is<string>())
)
),
order: 40
order: 10
);
builder.Conventions.AddMethodMetadata(new ApiMethodAttribute(),
when: c =>
Expand All @@ -54,6 +54,8 @@ public void Configure(LayerConfigurator configurator)
conventions.Add(new InitializeUsingQueryParametersConvention(), order: -30);
conventions.Add(new InitializeUsingIdParameterConvention(domainModel), order: -30);
conventions.Add(new RichTransientInitializerIsGetResourceConvention(), order: -30);
conventions.Add(new LookUpTransientByIdConvention(domainModel), order: -30);
conventions.Add(new LookUpTransientsByIdsConvention(domainModel), order: -30);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Newtonsoft.Json;
using System.Net.Http.Json;

namespace Baked.Test.CodingStyle;

public class LookingUpTransientsById : TestServiceNfr
{
[Test]
public async Task TransientParameters()
{
var response = await Client.PostAsync("/method-samples/transient-parameters", JsonContent.Create(
new
{
transientId = "1"
}
));
dynamic? actual = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());

$"{actual?.id}".ShouldBe("1");
}

[Test]
public async Task TransientListParameters()
{
var response = await Client.PostAsync("/method-samples/transient-list-parameters", JsonContent.Create(
new
{
transientIds = new[] { "1", "2" },
otherTransientIds = new[] { "3", "4" },
}
));
dynamic? actual = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());

((int?)actual?.Count).ShouldBe(4);
$"{actual?[0].id}".ShouldBe("1");
}
}
18 changes: 17 additions & 1 deletion test/recipe/Baked.Test.Recipe.Service/Business/MethodSamples.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Baked.Test.Orm;
using Baked.Test.CodingStyle.RichTransient;
using Baked.Test.Orm;
using Microsoft.Extensions.Logging;

namespace Baked.Test.Business;
Expand Down Expand Up @@ -93,6 +94,21 @@ public Entity EntityParameters(Entity entity) =>
public IEnumerable<Entity> EntityListParameters(IEnumerable<Entity> entities, Entity[] otherEntities) =>
[.. entities, .. otherEntities];

/// <param name="transient">
/// Transient description
/// </param>
public RichTransientWithData TransientParameters(RichTransientWithData transient) =>
transient;

/// <param name="transients">
/// Transients description
/// </param>
/// <param name="otherTransients">
/// Other transients description
/// </param>
public IEnumerable<RichTransientWithData> TransientListParameters(IEnumerable<RichTransientWithData> transients, RichTransientWithData[] otherTransients) =>
[.. transients, .. otherTransients];

internal Internal Internal() =>
new();
}

0 comments on commit 1b8ee83

Please sign in to comment.