Skip to content
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

Add support for destination value in user implemented mapping methods #276

Open
furier opened this issue Mar 13, 2023 · 5 comments
Open
Labels
enhancement New feature or request

Comments

@furier
Copy link

furier commented Mar 13, 2023

Is your feature request related to a problem? Please describe.

Currently, the User implemented mapping methods feature in Mapperly only allows users to provide a method body that maps a single source type to a single destination type. However, in some scenarios, it may be necessary to have more control over the mapping process, such as when mapping optional values or when the user wants to choose which value (source or destination) to use for the destination property.

Describe the solution you'd like

I propose adding support for destination values in the User implemented mapping methods feature. This would allow users to specify which value (source or destination) to use for the destination property when mapping between objects.

For example, the following code snippet demonstrates how this feature might be used to map an optional value:

MyMapper.cs

[Mapper]
public partial class MyMapper
{
    public partial void MapPersonToPersonDto(Person source, PersonDto destination) { }

    private static int? FromOptional<T>(Optional<int?> source, int? destination) => source.HasValue ? source.Value : destination;
}

MyMapper.g.cs

[Mapper]
public partial class MyMapper
{
    public partial void MapPersonToPersonDto(Person source, PersonDto destination) 
    {
        destination.Id = source.Id;
        /* other mappings omitted for brevity */
        destination.Age = FromOptional(source.Age, destination.Age);
    }
}

With this change, users would have more control over how mappings are defined and could handle more complex mapping scenarios that are not possible with the current implementation.

@latonz
Copy link
Contributor

latonz commented Mar 17, 2023

I think your use case could be implemented by using the after map feature with an ignored property:

[Mapper]
public partial class MyMapper
{
    public void MapPersonToPersonDto(Person person, PersonDto destination)
    {
        MapPersonToPersonDtoInternal(person, destination);
        destination.Age = CustomAgeMapping(person, destination);
    }

    [MapperIgnoreTarget(nameof(PersonDto.Age))]
    private partial void MapPersonToPersonDtoInternal(Person person, PersonDto destination)
}

Would this work for your use case?

@furier
Copy link
Author

furier commented Mar 18, 2023

It would probably work but that would mean that the mapping was not generated for me and I would have to do that manually? Then the point of a mapper is kinda mute?

@EniacMlezi
Copy link

EniacMlezi commented Mar 28, 2023

Using the after map feature would not work in the case where PersonDto.Age is required and when using a non "void mapping method" (when not mapping to existing object instance)

[Mapper]
public partial class MyMapper
{
    public PersonDto MapPersonToPersonDto(Person person)
    {
        var personDto = MapPersonToPersonDtoInternal(person);  
        destination.Age = CustomAgeMapping(person, destination);
    }

    [MapperIgnoreTarget(nameof(PersonDto.Age))]
    private partial PersonDto MapPersonToPersonDtoInternal(Person person)  // ~ ERROR: Required property Age on mapping target type was not found on the mapping source type Person
}

@EniacMlezi
Copy link

Maybe fixing #103 would also cover this?

@johngambleubind
Copy link

I have a source UpsertModel which doesn't contain the Id or the createdTimestamp, but in my target model they are required constructor parameters. In the target model they are not publicly settable.

I'd like to be able to configure the mapper to pass these along somehow. These could be additional params to the mapping function, or decorated attributes, or something else.

What I don't want to do is modify my target model. For now though I'm forced to add a SetId(...) and SetCreatedTimestamp(...) method to the target model class. Sad.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants