-
-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add
MapDerivedType
for existing target type mapping
- Loading branch information
1 parent
574cef7
commit 0251794
Showing
19 changed files
with
548 additions
and
9 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 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
82 changes: 82 additions & 0 deletions
82
src/Riok.Mapperly/Descriptors/Mappings/DerivedExistingTargetTypeSwitchMapping.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,82 @@ | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Riok.Mapperly.Descriptors.Mappings.ExistingTarget; | ||
using Riok.Mapperly.Emit.Syntax; | ||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | ||
using static Riok.Mapperly.Emit.Syntax.SyntaxFactoryHelper; | ||
|
||
namespace Riok.Mapperly.Descriptors.Mappings; | ||
|
||
/// <summary> | ||
/// A derived type mapping maps one base type or interface to another | ||
/// by implementing a switch statement over known types and performs the provided mapping for each type. | ||
/// </summary> | ||
public class DerivedExistingTargetTypeSwitchMapping( | ||
ITypeSymbol sourceType, | ||
ITypeSymbol targetType, | ||
IReadOnlyCollection<IExistingTargetMapping> existingTargetTypeMappings | ||
) : ExistingTargetMapping(sourceType, targetType) | ||
{ | ||
private const string SourceName = "source"; | ||
private const string TargetName = "target"; | ||
private const string GetTypeMethodName = nameof(GetType); | ||
|
||
public override IEnumerable<StatementSyntax> Build(TypeMappingBuildContext ctx, ExpressionSyntax target) | ||
{ | ||
var sourceExpression = TupleExpression(CommaSeparatedList(Argument(ctx.Source), Argument(target))); | ||
var caseSections = existingTargetTypeMappings.Select(x => BuildSwitchSection(ctx, x)); | ||
var defaultSection = BuildDefaultSwitchSection(ctx, target); | ||
|
||
yield return ctx.SyntaxFactory | ||
.SwitchStatement(sourceExpression, caseSections, defaultSection) | ||
.AddLeadingLineFeed(ctx.SyntaxFactory.Indentation); | ||
} | ||
|
||
private SwitchSectionSyntax BuildSwitchSection(TypeMappingBuildContext ctx, IExistingTargetMapping mapping) | ||
{ | ||
var (sectionCtx, sourceVariableName) = ctx.WithNewScopedSource(SourceName); | ||
var targetVariableName = sectionCtx.NameBuilder.New(TargetName); | ||
sectionCtx = sectionCtx.AddIndentation(); | ||
|
||
// (A source, B target) | ||
var positionalTypeMatch = PositionalPatternClause( | ||
CommaSeparatedList( | ||
Subpattern(DeclarationPattern(mapping.SourceType, sourceVariableName)), | ||
Subpattern(DeclarationPattern(mapping.TargetType, targetVariableName)) | ||
) | ||
); | ||
var pattern = RecursivePattern().WithPositionalPatternClause(positionalTypeMatch); | ||
|
||
// case (A source, B target): | ||
var caseLabel = CasePatternSwitchLabel(pattern).AddLeadingLineFeed(sectionCtx.SyntaxFactory.Indentation); | ||
|
||
// break; | ||
var statementContext = sectionCtx.AddIndentation(); | ||
var breakStatement = BreakStatement().AddLeadingLineFeed(statementContext.SyntaxFactory.Indentation); | ||
var target = IdentifierName(targetVariableName); | ||
var statements = mapping.Build(statementContext, target).Append(breakStatement); | ||
|
||
return SwitchSection(caseLabel, statements); | ||
} | ||
|
||
private SwitchSectionSyntax BuildDefaultSwitchSection(TypeMappingBuildContext ctx, ExpressionSyntax target) | ||
{ | ||
// default: | ||
var sectionCtx = ctx.SyntaxFactory.AddIndentation(); | ||
var defaultCaseLabel = DefaultSwitchLabel().AddLeadingLineFeed(sectionCtx.Indentation); | ||
|
||
// throw new ArgumentException(msg, nameof(ctx.Source)), | ||
var sourceType = Invocation(MemberAccess(ctx.Source, GetTypeMethodName)); | ||
var targetType = Invocation(MemberAccess(target, GetTypeMethodName)); | ||
var statementContext = sectionCtx.AddIndentation(); | ||
var throwExpression = ThrowArgumentExpression( | ||
InterpolatedString($"Cannot map {sourceType} to {targetType} as there is no known derived type mapping"), | ||
ctx.Source | ||
) | ||
.AddLeadingLineFeed(statementContext.Indentation); | ||
|
||
var statements = new StatementSyntax[] { ExpressionStatement(throwExpression) }; | ||
|
||
return SwitchSection(defaultCaseLabel, statements); | ||
} | ||
} |
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
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
7 changes: 7 additions & 0 deletions
7
test/Riok.Mapperly.IntegrationTests/Models/ExistingObjectBase.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,7 @@ | ||
namespace Riok.Mapperly.IntegrationTests.Models | ||
{ | ||
public class ExistingObjectBase | ||
{ | ||
public int Value { get; set; } | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
test/Riok.Mapperly.IntegrationTests/Models/ExistingObjectTypeA.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,7 @@ | ||
namespace Riok.Mapperly.IntegrationTests.Models | ||
{ | ||
public class ExistingObjectTypeA : ExistingObjectBase | ||
{ | ||
public int ValueA { get; set; } | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
test/Riok.Mapperly.IntegrationTests/Models/ExistingObjectTypeB.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,7 @@ | ||
namespace Riok.Mapperly.IntegrationTests.Models | ||
{ | ||
public class ExistingObjectTypeB : ExistingObjectBase | ||
{ | ||
public int ValueB { get; set; } | ||
} | ||
} |
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.