-
-
Notifications
You must be signed in to change notification settings - Fork 155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
POC Extra parameters #622
POC Extra parameters #622
Conversation
Thank you for this PR 🚀 I did not start the code review yet, I'll review it in the upcoming days. Overall this looks like a promising feature 😊 I prefer the simple approach of not passing the additional parameters, because otherwise it can become really hard to understand when which methods are invoked/generated and why. Regarding your description of the PR:
I don't get this. Do you mean
In a first version of this feature, I would not pass additional parameters anywhere, too keep it simple. Otherwise this could get quite complex when and why another method is called/generated. I'm not even sure if there is demand for this advanced feature. For now if this is needed, it is always possible to make keep a context inside the mapper class, instantiate a mapper with the context and use after map to set these fields. |
Thanks, please don't spend too much time reviewing this, it will likely change if I modify it. I would appreciate some pointers with my abstractions, i.e. should
The previous PR would create the following. public record UserInfo (int Id);;
public record UserDto(string UserId, ...);
public static partial UserDto MapTo(SourceInfo src, UserInfo user);
// generates the following
public static partial UserDto MapTo(SourceInfo src, UserInfo user)
{
var target = new UserDto(user.Id, ...);
return target;
} Here the extra parameter named public static partial DogDto Map(Dog dog)
// does not generate
target.DogOwnder = dog.Owner; On the other hand, extra parameters already diverge from the source parameter by using their name. So not having this behaviour could also be confusing. I can readd this.
I agree 😊. As I found before, passing extra parameters to auto-generated methods means you have to account for scopes/configuration contexts. I had to monkey-patch a way of changing the order of mapping generation from a simple queue into a recursive depth-first generator while also accounting for loops. I was thinking of how to support extra parameters for user implemented and defined mappers. This wouldn't have the above issues. We can see if this is needed. For example in the below code, mapperly could use the user defined method [Mapper(EnumMappingStrategy = EnumMappingStrategy.ByName)]
public static partial class CarMapper
{
[MapProperty(nameof(Car.Manufacturer), nameof(CarDto.Producer))] // Map property with a different name in the target type
public static partial CarDto MapCarToDto(Car car, string name);
public static ProducerDto MapProducer(Producer src, string name)
{
// ...
}
} |
I converted this PR to draft for now.
I think this would still result in weird behaviours. For example if the Car has a property of type Tire which then has a property of type Producer. The mapping of the tire is not user implemented but generated (without the name parameter). Then the user implemented |
Great point, this and the method resolution issues could make this pretty janky. Thankfully I'll add member resolution for extra parameters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did a quick review but I think a lot of code will change when we only consider additional parameters in the user defined mapping methods and don't pass them anywhere. Therefore I'll do a complete review once this is adjusted 😊
I added the few things I noticed as review feedback.
// return false; | ||
// } | ||
var extraParams = method.Parameters | ||
.Skip(expectedParameterCount) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of skipping the expected parameter count, keep a set of already processed parameter ordinals and check the additional parameter ordinals are not included in this set.
} | ||
|
||
public ITypeSymbol SourceType { get; } | ||
|
||
public ITypeSymbol TargetType { get; } | ||
|
||
public ImmutableEquatableArray<MethodParameter> Parameters { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the approach that we never pass parameters to other methods, only user defined mapping methods should not support parameters. For eg. user implemented mappings a diagnostic should be emitted if additional parameters are provided (RMG001).
@@ -162,4 +181,17 @@ private void AddUnmatchedSourceMembersDiagnostics() | |||
); | |||
} | |||
} | |||
|
|||
private void AddUnmatchedParametersDiagnostics() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the current architecture, if the user defined mapping is not an object mapping (eg. string to int), RMG048 is not emitted.
10296b0
to
692d756
Compare
As there seems to be no updates for several weeks I'm closing this for now. Feel free to reopen / open a new PR with updates 😊 |
POC for #103. This is a simpler version of #550, parameters do not attempt to find a matching memberpath nor are they passed down to sub methods.
IMapping
has aImmutableEquatableArray<MethodParameter> Parameters
propertyMethodMapping
is not significantly changed.[MapProperty]
.Parameter usage
This PR has a simple way of using parameters, if a target member has the name
username
, mapperly will attempt to resolve this from the source parameter and then look for a parameter namedusername
.It will not attempt to a parameter with a matching memberpath i.e. given a member
username
match with parameter,User user)
whereuser.Name -> username
This does diverge from how the source parameters are treated, but given that extra parameters use their name to resolve paths, it perhaps makes more sense. This could easily be changed.
Method resolving
I believe that
user defined
mappers should be able to call otheruser defined/implemented
mappers if they have compatible signatures and paramters. I have not decided on the best approach for method resolving. Part of the challenge is choosing a resolving approach that will not prevent future changes.Parameter usage
should matching member paths be used?Approaches