-
-
Notifications
You must be signed in to change notification settings - Fork 143
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add option to use other mappers (#661)
- Loading branch information
Showing
34 changed files
with
1,138 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
--- | ||
sidebar_position: 5 | ||
description: Manually implement mappings | ||
--- | ||
|
||
import Tabs from '@theme/Tabs'; | ||
|
||
# User implemented mapping methods | ||
|
||
If Mapperly cannot generate a mapping, one can implement it manually simply by providing a method body in the mapper declaration: | ||
|
||
```csharp | ||
[Mapper] | ||
public partial class CarMapper | ||
{ | ||
public partial CarDto CarToCarDto(Car car); | ||
|
||
private int TimeSpanToHours(TimeSpan t) => t.Hours; | ||
} | ||
``` | ||
|
||
Whenever Mapperly needs a mapping from `TimeSpan` to `int` inside the `CarMapper` implementation, it will use the provided implementation. | ||
|
||
## Use external mappings | ||
|
||
Mapperly can also consider mappings implemented in other classes. | ||
In order for Mapperly to find the mappings, they must be made known with `UseMapper` / `UseStaticMapper`. | ||
|
||
<!-- do not indent this, it won't work, https://stackoverflow.com/a/67579641/3302887 --> | ||
|
||
<Tabs> | ||
<TabItem value="static" label="Static"> | ||
|
||
For static mappings, `UseStaticMapper` can be used: | ||
|
||
```csharp | ||
[Mapper] | ||
// highlight-start | ||
[UseStaticMapper<BananaMapper>] // for c# language level ≥ 11 | ||
[UseStaticMapper(typeof(BananaMapper))] // for c# language level < 11 | ||
// highlight-end | ||
public static partial class BoxMapper | ||
{ | ||
public static partial BananaBox MapBananaBox(BananaBoxDto dto); | ||
} | ||
|
||
public static class BananaMapper | ||
{ | ||
public static Banana MapBanana(BananaDto dto) | ||
=> new Banana(dto.Weigth); | ||
} | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="instance" label="Instance"> | ||
|
||
To use the mappings of an object instance `UseMapper` can be used: | ||
|
||
```csharp | ||
[Mapper] | ||
public static partial class BoxMapper | ||
{ | ||
// highlight-start | ||
[UseMapper] | ||
private readonly BananaMapper _bananaMapper = new(); | ||
// highlight-end | ||
public static partial BananaBox MapBananaBox(BananaBoxDto dto); | ||
} | ||
|
||
public static class BananaMapper | ||
{ | ||
public static Banana MapBanana(BananaDto dto) | ||
=> new Banana(dto.Weigth); | ||
} | ||
``` | ||
|
||
:::info | ||
The initialization of fields and properties annotated with `UseMapper` needs to be done by the user. | ||
::: | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
Whenever Mapperly needs a mapping from `BananaBox` to `BananaBoxDto` inside the `BoxMapper` implementation, | ||
it will use the provided implementation by the `BananaMapper`. | ||
|
||
Used mappers themselves can be Mapperly backed classes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Riok.Mapperly.Abstractions; | ||
|
||
/// <summary> | ||
/// Considers all accessible mapping methods provided by the type of this member. | ||
/// Includes static and instance methods. | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] | ||
public sealed class UseMapperAttribute : Attribute { } |
21 changes: 21 additions & 0 deletions
21
src/Riok.Mapperly.Abstractions/UseStaticMapperAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
namespace Riok.Mapperly.Abstractions; | ||
|
||
/// <summary> | ||
/// Considers all static mapping methods provided by the type. | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] | ||
public sealed class UseStaticMapperAttribute : Attribute | ||
{ | ||
/// <summary> | ||
/// Considers all static mapping methods provided by the <paramref name="mapperType"/>. | ||
/// </summary> | ||
/// <param name="mapperType">The type of which mapping methods will be included.</param> | ||
public UseStaticMapperAttribute(Type mapperType) { } | ||
} | ||
|
||
/// <summary> | ||
/// Considers all static mapping methods provided by the generic type. | ||
/// </summary> | ||
/// <typeparam name="T">The type of which mapping methods will be included.</typeparam> | ||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] | ||
public sealed class UseStaticMapperAttribute<T> : Attribute { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
src/Riok.Mapperly/Configuration/UseStaticMapperConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Riok.Mapperly.Configuration; | ||
|
||
public record UseStaticMapperConfiguration(ITypeSymbol MapperType); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
src/Riok.Mapperly/Descriptors/ExternalMappings/ExternalMappingsExtractor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using Microsoft.CodeAnalysis; | ||
using Riok.Mapperly.Abstractions; | ||
using Riok.Mapperly.Configuration; | ||
using Riok.Mapperly.Descriptors.Mappings.UserMappings; | ||
using Riok.Mapperly.Diagnostics; | ||
using Riok.Mapperly.Helpers; | ||
|
||
namespace Riok.Mapperly.Descriptors.ExternalMappings; | ||
|
||
internal static class ExternalMappingsExtractor | ||
{ | ||
public static IEnumerable<IUserMapping> ExtractExternalMappings(SimpleMappingBuilderContext ctx, INamedTypeSymbol mapperSymbol) | ||
{ | ||
var staticExternalMappers = ctx.AttributeAccessor | ||
.Access<UseStaticMapperAttribute, UseStaticMapperConfiguration>(mapperSymbol) | ||
.Concat(ctx.AttributeAccessor.Access<UseStaticMapperAttribute<object>, UseStaticMapperConfiguration>(mapperSymbol)) | ||
.SelectMany( | ||
x => | ||
UserMethodMappingExtractor.ExtractUserImplementedMappings( | ||
ctx, | ||
x.MapperType, | ||
x.MapperType.FullyQualifiedIdentifierName(), | ||
true | ||
) | ||
); | ||
|
||
var externalInstanceMappers = ctx.SymbolAccessor | ||
.GetAllMembers(mapperSymbol) | ||
.Where(x => ctx.AttributeAccessor.HasAttribute<UseMapperAttribute>(x)) | ||
.SelectMany(x => ValidateAndExtractExternalInstanceMappings(ctx, x)); | ||
|
||
return staticExternalMappers.Concat(externalInstanceMappers); | ||
} | ||
|
||
private static IEnumerable<IUserMapping> ValidateAndExtractExternalInstanceMappings(SimpleMappingBuilderContext ctx, ISymbol symbol) | ||
{ | ||
var (name, type, nullableAnnotation) = symbol switch | ||
{ | ||
IFieldSymbol field => (field.Name, field.Type, field.NullableAnnotation), | ||
IPropertySymbol prop => (prop.Name, prop.Type, prop.NullableAnnotation), | ||
_ => (string.Empty, null, NullableAnnotation.None), | ||
}; | ||
|
||
if (type == null) | ||
return Enumerable.Empty<IUserMapping>(); | ||
|
||
if (nullableAnnotation != NullableAnnotation.Annotated) | ||
return UserMethodMappingExtractor.ExtractUserImplementedMappings(ctx, type, name, false); | ||
|
||
ctx.ReportDiagnostic(DiagnosticDescriptors.ExternalMapperMemberCannotBeNullable, symbol, symbol.ToDisplayString()); | ||
return Enumerable.Empty<IUserMapping>(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.