Adapt data to new MapTo feature

This commit is contained in:
CodeLiturgy 2022-08-18 16:46:20 +01:00
parent 3a2d3a1b41
commit e41fd2d815
16 changed files with 336 additions and 233 deletions

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq; using System.Linq;
using BlueWest.Data; using BlueWest.Data;
using BlueWest.WebApi.MySQL; using BlueWest.WebApi.MySQL;
@ -6,6 +7,9 @@ using Microsoft.AspNetCore.Mvc;
namespace BlueWest.WebApi.Controllers namespace BlueWest.WebApi.Controllers
{ {
/// <summary>
/// Controller responsible to get country data
/// </summary>
[ApiController] [ApiController]
[Route("[controller]")] [Route("[controller]")]
public class CountriesController : ControllerBase public class CountriesController : ControllerBase
@ -25,7 +29,7 @@ public class CountriesController : ControllerBase
/// <summary> /// <summary>
/// Add Country /// Add Country
/// </summary> /// </summary>
/// <param name="country"></param> /// <param name="countryToCreate">The country data to create</param>
/// <returns>The newly created country</returns> /// <returns>The newly created country</returns>
/// /// <summary> /// /// <summary>
/// Creates a Country. /// Creates a Country.
@ -44,11 +48,11 @@ public class CountriesController : ControllerBase
/// <response code="201">Returns the newly created country</response> /// <response code="201">Returns the newly created country</response>
[ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status201Created)]
[HttpPost] [HttpPost]
public ActionResult AddCountry(Country country) public ActionResult AddCountry(CountryCreate countryToCreate)
{ {
_dbContext.Countries.Add(country); _dbContext.Countries.Add(new Country(countryToCreate, new List<Currency>()));
_dbContext.SaveChanges(); _dbContext.SaveChanges();
return CreatedAtRoute(nameof(GetCountryById), new {countryId = country.Code}, country); return CreatedAtRoute(nameof(GetCountryById), new {countryId = countryToCreate.Code}, countryToCreate);
} }
/// <summary> /// <summary>

View File

@ -7,6 +7,9 @@ using Microsoft.AspNetCore.Mvc;
namespace BlueWest.WebApi.Controllers namespace BlueWest.WebApi.Controllers
{ {
/// <summary>
/// The controller responsible to fetch currency data
/// </summary>
[ApiController] [ApiController]
[Route("[controller]")] [Route("[controller]")]
public class CurrenciesController : ControllerBase public class CurrenciesController : ControllerBase
@ -19,16 +22,27 @@ namespace BlueWest.WebApi.Controllers
} }
/// <summary>
/// Add Currency to the table of currencies
/// </summary>
/// <param name="currencyToCreate">Currency data to create</param>
/// <returns></returns>
[ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status201Created)]
[HttpPost] [HttpPost]
public ActionResult AddCurrency(CurrencyCreate currency) public ActionResult AddCurrency(CurrencyCreate currencyToCreate)
{ {
var newCurrency = new Currency(); var newCurrency = new Currency(currencyToCreate, new List<Country>());
_dbContext.Currencies.Add(newCurrency); _dbContext.Currencies.Add(newCurrency);
_dbContext.SaveChanges(); _dbContext.SaveChanges();
return CreatedAtRoute(nameof(GetCurrencyById), new {CurrencyId = currency.Code}, currency); return CreatedAtRoute(nameof(GetCurrencyById), new {CurrencyId = currencyToCreate.Code}, currencyToCreate);
} }
/// <summary>
/// Update a currency data from the Currency table in the database
/// </summary>
/// <param name="currencyNumber">The currency number we want to update</param>
/// <param name="currencyToUpdate">Currency Data to update</param>
/// <returns></returns>
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status400BadRequest)]
[HttpPut("{currencyNumber}")] [HttpPut("{currencyNumber}")]
@ -48,6 +62,11 @@ namespace BlueWest.WebApi.Controllers
} }
/// <summary>
/// Gets a currency by the currency number (id)
/// </summary>
/// <param name="currencyId">The id of the currency to get</param>
/// <returns></returns>
[ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpGet("{currencyId}", Name = nameof(GetCurrencyById))] [HttpGet("{currencyId}", Name = nameof(GetCurrencyById))]

View File

@ -4,12 +4,14 @@ using MapTo;
namespace BlueWest.Data namespace BlueWest.Data
{ {
[MapFrom(typeof(CurrencyUpdate))] [MapFrom(new []{
typeof(CurrencyUpdate),
typeof(CurrencyCreate)})]
public partial class Currency public partial class Currency
{ {
[MaxLength(3)]public int Num { get; set; } // Primary key [MaxLength(3)] public int Num { get; set; } // Primary key
[MaxLength(3)]public string Code { get; set; } [MaxLength(3)] public string Code { get; set; }
public List<Country> Countries { get; set; } public List<Country> Countries { get; set; }
public Currency() public Currency()

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using MapTo; using MapTo;
namespace BlueWest.Data namespace BlueWest.Data
@ -8,7 +9,7 @@ namespace BlueWest.Data
public partial class CurrencyUpdate public partial class CurrencyUpdate
{ {
// ISO 4217 Code // ISO 4217 Code
public string Code { get; set; } [MaxLength(3)] public string Code { get; set; }
} }

View File

@ -30,18 +30,22 @@ namespace MapTo.Extensions
internal static SourceBuilder WriteModelInfo(this SourceBuilder builder, MappingModel model) internal static SourceBuilder WriteModelInfo(this SourceBuilder builder, MappingModel model)
{ {
var targetSourceType = model.MappedSourceTypes[0]; foreach (var targetSourceType in model.MappedSourceTypes)
return builder {
.WriteLine() builder
.WriteComment($" IsTypeUpdatable {model.IsTypeUpdatable}") .WriteLine()
.WriteComment($" HasMappedBaseClass {model.HasMappedBaseClass.ToString()}") .WriteComment($" IsTypeUpdatable {model.IsTypeUpdatable}")
.WriteComment($" Namespace {model.Namespace}") .WriteComment($" HasMappedBaseClass {model.HasMappedBaseClass.ToString()}")
.WriteComment($" Options {model.Options.ToString()}") .WriteComment($" Namespace {model.Namespace}")
.WriteComment($" Type {model.Type}") .WriteComment($" Options {model.Options.ToString()}")
.WriteComment($" TypeIdentifierName {model.TypeIdentifierName}") .WriteComment($" Type {model.Type}")
.WriteComment($" SourceNamespace {targetSourceType.SourceNamespace}") .WriteComment($" TypeIdentifierName {model.TypeIdentifierName}")
.WriteComment($" SourceTypeFullName {targetSourceType.SourceTypeFullName}") .WriteComment($" SourceNamespace {targetSourceType.SourceNamespace}")
.WriteComment($" SourceTypeIdentifierName {targetSourceType.SourceTypeIdentifierName}"); .WriteComment($" SourceTypeFullName {targetSourceType.SourceTypeFullName}")
.WriteComment($" SourceTypeIdentifierName {targetSourceType.SourceTypeIdentifierName}");
}
return builder;
} }

View File

@ -15,7 +15,6 @@ namespace MapTo.Extensions
{ {
const bool writeDebugInfo = true; const bool writeDebugInfo = true;
var targetSourceType = model.MappedSourceTypes[0];
using var builder = new SourceBuilder() using var builder = new SourceBuilder()
.WriteLine(GeneratedFilesHeader) .WriteLine(GeneratedFilesHeader)
@ -27,23 +26,30 @@ namespace MapTo.Extensions
.WriteLine($"namespace {model.Namespace}") .WriteLine($"namespace {model.Namespace}")
.WriteOpeningBracket(); .WriteOpeningBracket();
if (writeDebugInfo)
builder
.WriteModelInfo(model) foreach (var targetSourceType in model.MappedSourceTypes)
.WriteLine() {
.WriteComment("Type properties") if (writeDebugInfo)
.WriteComment() builder
.WriteMappedProperties(targetSourceType.TypeProperties) .WriteModelInfo(model)
.WriteLine() .WriteLine()
.WriteComment("Source properties") .WriteComment("Type properties")
.WriteLine() .WriteComment()
.WriteComment("Type fields") .WriteMappedProperties(targetSourceType.TypeProperties)
.WriteComment() .WriteLine()
.WriteMappedProperties(targetSourceType.TypeFields) .WriteComment("Source properties")
.WriteLine() .WriteLine()
.WriteComment("Source fields") .WriteComment("Type fields")
.WriteMappedProperties(targetSourceType.SourceFields) .WriteComment()
.WriteLine(); .WriteMappedProperties(targetSourceType.TypeFields)
.WriteLine()
.WriteComment("Source fields")
.WriteMappedProperties(targetSourceType.SourceFields)
.WriteLine();
}
builder builder
// Class declaration // Class declaration
@ -52,10 +58,14 @@ namespace MapTo.Extensions
.WriteLine() .WriteLine()
// Class body // Class body
.GeneratePublicConstructor(model); .GeneratePublicConstructor(model);
foreach (var targetSourceType in model.MappedSourceTypes)
{
if (model.IsTypeUpdatable && targetSourceType.TypeProperties.GetWritableMappedProperties().Length > 0) builder.GenerateUpdateMethod(model);
if (model.IsTypeUpdatable && targetSourceType.TypeFields.GetWritableMappedProperties().Length > 0) builder.GenerateUpdateMethod(model);
}
if (model.IsJsonExtension) builder.WriteToJsonMethod(model); if (model.IsJsonExtension) builder.WriteToJsonMethod(model);
if (model.IsTypeUpdatable && targetSourceType.TypeProperties.GetWritableMappedProperties().Length > 0) builder.GenerateUpdateMethod(model);
if (model.IsTypeUpdatable && targetSourceType.TypeFields.GetWritableMappedProperties().Length > 0) builder.GenerateUpdateMethod(model);
builder builder
.WriteLine() .WriteLine()
@ -70,46 +80,47 @@ namespace MapTo.Extensions
private static SourceBuilder GeneratePublicConstructor(this SourceBuilder builder, MappingModel model) private static SourceBuilder GeneratePublicConstructor(this SourceBuilder builder, MappingModel model)
{ {
var targetSourceType = model.MappedSourceTypes[0];
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
const string mappingContextParameterName = "context"; const string mappingContextParameterName = "context";
var baseConstructor = /*model.HasMappedBaseClass ? $" : base({mappingContextParameterName}, {sourceClassParameterName})" :*/ string.Empty; foreach (var targetSourceType in model.MappedSourceTypes)
var stringBuilder = new StringBuilder();
var otherProperties = new List<MappedMember>();
foreach (var property in targetSourceType.TypeProperties)
{ {
if (!targetSourceType.SourceProperties.IsMappedProperty(property)) var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
var baseConstructor = /*model.HasMappedBaseClass ? $" : base({mappingContextParameterName}, {sourceClassParameterName})" :*/ string.Empty;
var stringBuilder = new StringBuilder();
var otherProperties = new List<MappedMember>();
foreach (var property in targetSourceType.TypeProperties)
{ {
stringBuilder.Append(", "); if (!targetSourceType.SourceProperties.IsMappedProperty(property))
stringBuilder.Append($"{property.FullyQualifiedType} {property.SourcePropertyName.ToCamelCase()}"); {
otherProperties.Add(property); stringBuilder.Append(", ");
} stringBuilder.Append($"{property.FullyQualifiedType} {property.SourcePropertyName.ToCamelCase()}");
} otherProperties.Add(property);
}
foreach (var property in targetSourceType.TypeFields) }
{ foreach (var property in targetSourceType.TypeFields)
if (!targetSourceType.SourceFields.IsMappedProperty(property))
{ {
stringBuilder.Append(", "); if (!targetSourceType.SourceFields.IsMappedProperty(property))
stringBuilder.Append($"{property.FullyQualifiedType} {property.SourcePropertyName.ToCamelCase()}"); {
otherProperties.Add(property); stringBuilder.Append(", ");
stringBuilder.Append($"{property.FullyQualifiedType} {property.SourcePropertyName.ToCamelCase()}");
otherProperties.Add(property);
}
} }
var readOnlyPropertiesArguments = stringBuilder.ToString();
builder
.WriteLine($"public {model.TypeIdentifierName}({targetSourceType.SourceType} {sourceClassParameterName}{readOnlyPropertiesArguments}){baseConstructor}")
.WriteOpeningBracket()
.WriteAssignmentMethod(model, otherProperties.ToArray().ToImmutableArray(), sourceClassParameterName, mappingContextParameterName, false);
builder.WriteClosingBracket();
} }
var readOnlyPropertiesArguments = stringBuilder.ToString();
builder
.WriteLine($"public {model.TypeIdentifierName}({targetSourceType.SourceType} {sourceClassParameterName}{readOnlyPropertiesArguments}){baseConstructor}")
.WriteOpeningBracket()
.WriteAssignmentMethod(model, otherProperties.ToArray().ToImmutableArray(), sourceClassParameterName, mappingContextParameterName, false);
// End constructor declaration // End constructor declaration
return builder.WriteClosingBracket(); return builder;
} }
private static bool IsMappedProperty(this System.Collections.Immutable.ImmutableArray<MappedMember> properties, MappedMember property) private static bool IsMappedProperty(this System.Collections.Immutable.ImmutableArray<MappedMember> properties, MappedMember property)
@ -131,29 +142,33 @@ namespace MapTo.Extensions
.WriteLine("var stringBuilder = new System.Text.StringBuilder();") .WriteLine("var stringBuilder = new System.Text.StringBuilder();")
.WriteLine(GetStringBuilderAppendNoInterpolation("{")); .WriteLine(GetStringBuilderAppendNoInterpolation("{"));
var targetSourceType = model.MappedSourceTypes[0]; foreach (var targetSourceType in model.MappedSourceTypes)
foreach (var property in targetSourceType.TypeProperties)
{ {
if (!property.isEnumerable) foreach (var property in targetSourceType.TypeProperties)
HandlePropertyEnumerable(builder, property);
else
{ {
builder = WriteJsonField(builder, property); if (!property.isEnumerable)
HandlePropertyEnumerable(builder, property);
else
{
builder = WriteJsonField(builder, property);
}
} }
} foreach (var property in targetSourceType.TypeFields)
foreach (var property in targetSourceType.TypeFields)
{
if (!property.isEnumerable)
HandleFieldEnumerable(builder, property);
else
{ {
builder.WriteLine(GetStringBuilderAppend($"\\\"{property.Name.ToCamelCase()}\\\" : [{GetJsonArrayValue(property, ref builder)}],")); if (!property.isEnumerable)
HandleFieldEnumerable(builder, property);
else
{
builder.WriteLine(GetStringBuilderAppend($"\\\"{property.Name.ToCamelCase()}\\\" : [{GetJsonArrayValue(property, ref builder)}],"));
}
} }
builder.WriteLine(GetStringBuilderAppendNoInterpolation("}"));
builder.WriteLine("return stringBuilder.ToString();");
builder.WriteClosingBracket();
} }
builder.WriteLine(GetStringBuilderAppendNoInterpolation("}"));
builder.WriteLine("return stringBuilder.ToString();");
builder.WriteClosingBracket();
return builder; return builder;
} }
@ -231,33 +246,48 @@ namespace MapTo.Extensions
private static SourceBuilder WriteAssignmentMethod(this SourceBuilder builder, MappingModel model, System.Collections.Immutable.ImmutableArray<MappedMember>? otherProperties, private static SourceBuilder WriteAssignmentMethod(this SourceBuilder builder, MappingModel model, System.Collections.Immutable.ImmutableArray<MappedMember>? otherProperties,
string? sourceClassParameterName, string mappingContextParameterName, bool fromUpdate) string? sourceClassParameterName, string mappingContextParameterName, bool fromUpdate)
{ {
var targetSourceType = model.MappedSourceTypes[0];
foreach (var property in targetSourceType.SourceProperties) List<MappedMember> _addedMembers = new List<MappedMember>();
foreach (var targetSourceType in model.MappedSourceTypes)
{ {
if (property.isReadOnly && fromUpdate) continue; foreach (var property in targetSourceType.SourceProperties)
{
if (property.isReadOnly && fromUpdate) continue;
if(_addedMembers.Contains(property)) continue;
builder.WriteLine($"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName};");
builder.WriteLine($"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName};");
_addedMembers.Add(property);
}
foreach (var property in targetSourceType.SourceFields)
{
if (property.isReadOnly && fromUpdate) continue;
if(_addedMembers.Contains(property)) continue;
builder.WriteLine($"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName};");
_addedMembers.Add(property);
}
if (otherProperties == null) return builder;
foreach (var property in otherProperties)
{
if(_addedMembers.Contains(property)) continue;
builder.WriteLine(property.MappedSourcePropertyTypeName is null
? $"{property.Name} = {property.SourcePropertyName.ToCamelCase()};"
: "");
_addedMembers.Add(property);
}
} }
foreach (var property in targetSourceType.SourceFields)
{
if (property.isReadOnly && fromUpdate) continue;
builder.WriteLine($"{property.Name} = {sourceClassParameterName}.{property.SourcePropertyName};");
}
if (otherProperties == null) return builder;
foreach (var property in otherProperties)
{
builder.WriteLine(property.MappedSourcePropertyTypeName is null
? $"{property.Name} = {property.SourcePropertyName.ToCamelCase()};"
: "");
}
return builder; return builder;
@ -266,15 +296,19 @@ namespace MapTo.Extensions
private static SourceBuilder GenerateUpdateMethod(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateUpdateMethod(this SourceBuilder builder, MappingModel model)
{ {
var targetSourceType = model.MappedSourceTypes[0];
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
builder foreach (var targetSourceType in model.MappedSourceTypes)
.GenerateUpdaterMethodsXmlDocs(model, sourceClassParameterName) {
.WriteLine($"public void Update({targetSourceType.SourceType} {sourceClassParameterName})") var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
.WriteOpeningBracket()
.WriteAssignmentMethod(model, null, sourceClassParameterName, "context", true) builder
.WriteClosingBracket(); .GenerateUpdaterMethodsXmlDocs(model, sourceClassParameterName)
.WriteLine($"public void Update({targetSourceType.SourceType} {sourceClassParameterName})")
.WriteOpeningBracket()
.WriteAssignmentMethod(model, null, sourceClassParameterName, "context", true)
.WriteClosingBracket();
}
return builder; return builder;
} }
@ -286,28 +320,37 @@ namespace MapTo.Extensions
return builder; return builder;
} }
var targetSourceType = model.MappedSourceTypes[0]; foreach (var targetSourceType in model.MappedSourceTypes)
{
builder
.WriteLine("/// <summary>")
.WriteLine($"/// Updates <see cref=\"{model.TypeIdentifierName}\"/> and sets its participating properties")
.WriteLine($"/// using the property values from <paramref name=\"{sourceClassParameterName}\"/>.")
.WriteLine("/// </summary>")
.WriteLine($"/// <param name=\"{sourceClassParameterName}\">The instance of <see cref=\"{targetSourceType.SourceType}\"/> to use as source.</param>");
return builder }
.WriteLine("/// <summary>")
.WriteLine($"/// Updates <see cref=\"{model.TypeIdentifierName}\"/> and sets its participating properties") return builder;
.WriteLine($"/// using the property values from <paramref name=\"{sourceClassParameterName}\"/>.")
.WriteLine("/// </summary>")
.WriteLine($"/// <param name=\"{sourceClassParameterName}\">The instance of <see cref=\"{targetSourceType.SourceType}\"/> to use as source.</param>");
} }
private static SourceBuilder GenerateEnumerableJsonSourceTypeExtensionMethod(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateEnumerableJsonSourceTypeExtensionMethod(this SourceBuilder builder, MappingModel model)
{ {
var targetSourceType = model.MappedSourceTypes[0];
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase(); foreach (var targetSourceType in model.MappedSourceTypes)
{
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
return builder builder
.WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]") .WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]")
.WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static string ToJson(this IEnumerable<{targetSourceType.SourceType}{model.Options.NullableReferenceSyntax}> {sourceClassParameterName}List)") .WriteLine($"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static string ToJson(this IEnumerable<{targetSourceType.SourceType}{model.Options.NullableReferenceSyntax}> {sourceClassParameterName}List)")
.WriteOpeningBracket() .WriteOpeningBracket()
.WriteLine($"return {sourceClassParameterName} == null ? null : new {model.TypeIdentifierName}({sourceClassParameterName});") .WriteLine($"return {sourceClassParameterName} == null ? null : new {model.TypeIdentifierName}({sourceClassParameterName});")
.WriteClosingBracket(); .WriteClosingBracket();
}
return builder;
} }
} }
} }

View File

@ -22,15 +22,18 @@ namespace MapTo.Sources
.WriteLine($"partial record {model.TypeIdentifierName}") .WriteLine($"partial record {model.TypeIdentifierName}")
.WriteOpeningBracket(); .WriteOpeningBracket();
var targetSourceType = model.MappedSourceTypes[0]; foreach (var targetSourceType in model.MappedSourceTypes)
{
if (targetSourceType.GenerateSecondaryConstructor)
{
builder
.GenerateSecondaryConstructor(model)
.WriteLine();
}
}
// Class body // Class body
if (targetSourceType.GenerateSecondaryConstructor)
{
builder
.GenerateSecondaryConstructor(model)
.WriteLine();
}
builder builder
.GeneratePrivateConstructor(model) .GeneratePrivateConstructor(model)
@ -55,105 +58,118 @@ namespace MapTo.Sources
private static SourceBuilder GenerateSecondaryConstructor(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateSecondaryConstructor(this SourceBuilder builder, MappingModel model)
{ {
// grab first data from array // grab first data from array
var targetSourceType = model.MappedSourceTypes[0];
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
if (model.Options.GenerateXmlDocument) foreach (var targetSourceType in model.MappedSourceTypes)
{ {
builder var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
.WriteLine("/// <summary>") if (model.Options.GenerateXmlDocument)
.WriteLine($"/// Initializes a new instance of the <see cref=\"{model.TypeIdentifierName}\"/> class") {
.WriteLine($"/// using the property values from the specified <paramref name=\"{sourceClassParameterName}\"/>.") builder
.WriteLine("/// </summary>") .WriteLine("/// <summary>")
.WriteLine($"/// <exception cref=\"ArgumentNullException\">{sourceClassParameterName} is null</exception>"); .WriteLine($"/// Initializes a new instance of the <see cref=\"{model.TypeIdentifierName}\"/> class")
.WriteLine($"/// using the property values from the specified <paramref name=\"{sourceClassParameterName}\"/>.")
.WriteLine("/// </summary>")
.WriteLine($"/// <exception cref=\"ArgumentNullException\">{sourceClassParameterName} is null</exception>");
}
builder .WriteLine($"{model.Options.ConstructorAccessModifier.ToLowercaseString()} {model.TypeIdentifierName}({targetSourceType.SourceType} {sourceClassParameterName})")
.WriteLine($" : this(new {MappingContextSource.ClassName}(), {sourceClassParameterName}) {{ }}");
} }
return builder
.WriteLine($"{model.Options.ConstructorAccessModifier.ToLowercaseString()} {model.TypeIdentifierName}({targetSourceType.SourceType} {sourceClassParameterName})")
.WriteLine($" : this(new {MappingContextSource.ClassName}(), {sourceClassParameterName}) {{ }}"); return builder;
} }
private static SourceBuilder GeneratePrivateConstructor(this SourceBuilder builder, MappingModel model) private static SourceBuilder GeneratePrivateConstructor(this SourceBuilder builder, MappingModel model)
{ {
var targetSourceType = model.MappedSourceTypes[0];
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
const string mappingContextParameterName = "context"; const string mappingContextParameterName = "context";
builder foreach (var targetSourceType in model.MappedSourceTypes)
.WriteLine($"private protected {model.TypeIdentifierName}({MappingContextSource.ClassName} {mappingContextParameterName}, {targetSourceType.SourceType} {sourceClassParameterName})") {
.Indent() var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
.Write(": this("). builder
.WriteLine(
WriteProperties(model, sourceClassParameterName, mappingContextParameterName) $"private protected {model.TypeIdentifierName}({MappingContextSource.ClassName} {mappingContextParameterName}, {targetSourceType.SourceType} {sourceClassParameterName})")
.Indent()
.WriteLine(")") .Write(": this(").WriteProperties(model, sourceClassParameterName, mappingContextParameterName)
.Unindent() .WriteLine(")")
.WriteOpeningBracket() .Unindent()
.WriteLine($"if ({mappingContextParameterName} == null) throw new ArgumentNullException(nameof({mappingContextParameterName}));") .WriteOpeningBracket()
.WriteLine($"if ({sourceClassParameterName} == null) throw new ArgumentNullException(nameof({sourceClassParameterName}));") .WriteLine($"if ({mappingContextParameterName} == null) throw new ArgumentNullException(nameof({mappingContextParameterName}));")
.WriteLine() .WriteLine($"if ({sourceClassParameterName} == null) throw new ArgumentNullException(nameof({sourceClassParameterName}));")
.WriteLine($"{mappingContextParameterName}.{MappingContextSource.RegisterMethodName}({sourceClassParameterName}, this);"); .WriteLine()
.WriteLine($"{mappingContextParameterName}.{MappingContextSource.RegisterMethodName}({sourceClassParameterName}, this);")
.WriteClosingBracket();
}
// End constructor declaration // End constructor declaration
return builder.WriteClosingBracket(); return builder;
} }
private static SourceBuilder WriteProperties(this SourceBuilder builder, MappingModel model, string sourceClassParameterName, private static SourceBuilder WriteProperties(this SourceBuilder builder, MappingModel model, string sourceClassParameterName,
string mappingContextParameterName) string mappingContextParameterName)
{ {
var targetSourceType = model.MappedSourceTypes[0];
for (var i = 0; i < targetSourceType.SourceProperties.Length; i++) foreach (var targetSourceType in model.MappedSourceTypes)
{ {
var property = targetSourceType.SourceProperties[i]; for (var i = 0; i < targetSourceType.SourceProperties.Length; i++)
if (property.TypeConverter is null)
{ {
if (property.IsEnumerable) var property = targetSourceType.SourceProperties[i];
if (property.TypeConverter is null)
{ {
builder.Write( if (property.IsEnumerable)
$"{property.Name}: {sourceClassParameterName}.{property.SourcePropertyName}.Select({mappingContextParameterName}.{MappingContextSource.MapMethodName}<{property.MappedSourcePropertyTypeName}, {property.EnumerableTypeArgument}>).ToList()"); {
builder.Write(
$"{property.Name}: {sourceClassParameterName}.{property.SourcePropertyName}.Select({mappingContextParameterName}.{MappingContextSource.MapMethodName}<{property.MappedSourcePropertyTypeName}, {property.EnumerableTypeArgument}>).ToList()");
}
else
{
builder.Write(property.MappedSourcePropertyTypeName is null
? $"{property.Name}: {sourceClassParameterName}.{property.SourcePropertyName}"
: $"{property.Name}: {mappingContextParameterName}.{MappingContextSource.MapMethodName}<{property.MappedSourcePropertyTypeName}, {property.Type}>({sourceClassParameterName}.{property.SourcePropertyName})");
}
} }
else else
{ {
builder.Write(property.MappedSourcePropertyTypeName is null var parameters = property.TypeConverterParameters.IsEmpty
? $"{property.Name}: {sourceClassParameterName}.{property.SourcePropertyName}" ? "null"
: $"{property.Name}: {mappingContextParameterName}.{MappingContextSource.MapMethodName}<{property.MappedSourcePropertyTypeName}, {property.Type}>({sourceClassParameterName}.{property.SourcePropertyName})"); : $"new object[] {{ {string.Join(", ", property.TypeConverterParameters)} }}";
builder.Write(
$"{property.Name}: new {property.TypeConverter}().Convert({sourceClassParameterName}.{property.SourcePropertyName}, {parameters})");
}
if (i < targetSourceType.SourceProperties.Length - 1)
{
builder.Write(", ");
} }
} }
else
{
var parameters = property.TypeConverterParameters.IsEmpty
? "null"
: $"new object[] {{ {string.Join(", ", property.TypeConverterParameters)} }}";
builder.Write(
$"{property.Name}: new {property.TypeConverter}().Convert({sourceClassParameterName}.{property.SourcePropertyName}, {parameters})");
}
if (i < targetSourceType.SourceProperties.Length - 1)
{
builder.Write(", ");
}
} }
return builder; return builder;
} }
private static SourceBuilder GenerateFactoryMethod(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateFactoryMethod(this SourceBuilder builder, MappingModel model)
{ {
var targetSourceType = model.MappedSourceTypes[0]; foreach (var targetSourceType in model.MappedSourceTypes)
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase(); {
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
return builder builder
.GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName) .GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName)
.WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]") .WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]")
.WriteLine( .WriteLine(
$"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.TypeIdentifierName}{model.Options.NullableReferenceSyntax} From({targetSourceType.SourceType}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})") $"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.TypeIdentifierName}{model.Options.NullableReferenceSyntax} From({targetSourceType.SourceType}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})")
.WriteOpeningBracket() .WriteOpeningBracket()
.WriteLine( .WriteLine(
$"return {sourceClassParameterName} == null ? null : {MappingContextSource.ClassName}.{MappingContextSource.FactoryMethodName}<{targetSourceType.SourceType}, {model.TypeIdentifierName}>({sourceClassParameterName});") $"return {sourceClassParameterName} == null ? null : {MappingContextSource.ClassName}.{MappingContextSource.FactoryMethodName}<{targetSourceType.SourceType}, {model.TypeIdentifierName}>({sourceClassParameterName});")
.WriteClosingBracket(); .WriteClosingBracket();
}
return builder;
} }
private static SourceBuilder GenerateConvertorMethodsXmlDocs(this SourceBuilder builder, MappingModel model, string sourceClassParameterName) private static SourceBuilder GenerateConvertorMethodsXmlDocs(this SourceBuilder builder, MappingModel model, string sourceClassParameterName)
@ -162,44 +178,58 @@ namespace MapTo.Sources
{ {
return builder; return builder;
} }
var targetSourceType = model.MappedSourceTypes[0];
return builder foreach (var targetSourceType in model.MappedSourceTypes)
.WriteLine("/// <summary>") {
.WriteLine($"/// Creates a new instance of <see cref=\"{model.TypeIdentifierName}\"/> and sets its participating properties") builder
.WriteLine($"/// using the property values from <paramref name=\"{sourceClassParameterName}\"/>.") .WriteLine("/// <summary>")
.WriteLine("/// </summary>") .WriteLine($"/// Creates a new instance of <see cref=\"{model.TypeIdentifierName}\"/> and sets its participating properties")
.WriteLine($"/// <param name=\"{sourceClassParameterName}\">The instance of <see cref=\"{targetSourceType.SourceType}\"/> to use as source.</param>") .WriteLine($"/// using the property values from <paramref name=\"{sourceClassParameterName}\"/>.")
.WriteLine( .WriteLine("/// </summary>")
$"/// <returns>A new instance of <see cred=\"{model.TypeIdentifierName}\"/> -or- <c>null</c> if <paramref name=\"{sourceClassParameterName}\"/> is <c>null</c>.</returns>"); .WriteLine($"/// <param name=\"{sourceClassParameterName}\">The instance of <see cref=\"{targetSourceType.SourceType}\"/> to use as source.</param>")
.WriteLine(
$"/// <returns>A new instance of <see cred=\"{model.TypeIdentifierName}\"/> -or- <c>null</c> if <paramref name=\"{sourceClassParameterName}\"/> is <c>null</c>.</returns>");
}
return builder;
} }
private static SourceBuilder GenerateSourceTypeExtensionClass(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateSourceTypeExtensionClass(this SourceBuilder builder, MappingModel model)
{ {
var targetSourceType = model.MappedSourceTypes[0]; foreach (var targetSourceType in model.MappedSourceTypes)
{
builder
.WriteLine(
$"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static partial class {targetSourceType.SourceTypeIdentifierName}To{model.TypeIdentifierName}Extensions")
.WriteOpeningBracket()
.GenerateSourceTypeExtensionMethod(model)
.WriteClosingBracket();
}
return builder return builder;
.WriteLine(
$"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static partial class {targetSourceType.SourceTypeIdentifierName}To{model.TypeIdentifierName}Extensions")
.WriteOpeningBracket()
.GenerateSourceTypeExtensionMethod(model)
.WriteClosingBracket();
} }
private static SourceBuilder GenerateSourceTypeExtensionMethod(this SourceBuilder builder, MappingModel model) private static SourceBuilder GenerateSourceTypeExtensionMethod(this SourceBuilder builder, MappingModel model)
{ {
var targetSourceType = model.MappedSourceTypes[0];
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase(); foreach (var targetSourceType in model.MappedSourceTypes)
{
var sourceClassParameterName = targetSourceType.SourceTypeIdentifierName.ToCamelCase();
return builder builder
.GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName) .GenerateConvertorMethodsXmlDocs(model, sourceClassParameterName)
.WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]") .WriteLineIf(model.Options.SupportNullableStaticAnalysis, $"[return: NotNullIfNotNull(\"{sourceClassParameterName}\")]")
.WriteLine( .WriteLine(
$"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.TypeIdentifierName}{model.Options.NullableReferenceSyntax} To{model.TypeIdentifierName}(this {targetSourceType.SourceType}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})") $"{model.Options.GeneratedMethodsAccessModifier.ToLowercaseString()} static {model.TypeIdentifierName}{model.Options.NullableReferenceSyntax} To{model.TypeIdentifierName}(this {targetSourceType.SourceType}{model.Options.NullableReferenceSyntax} {sourceClassParameterName})")
.WriteOpeningBracket() .WriteOpeningBracket()
.WriteLine($"return {sourceClassParameterName} == null ? null : new {model.TypeIdentifierName}({sourceClassParameterName});") .WriteLine($"return {sourceClassParameterName} == null ? null : new {model.TypeIdentifierName}({sourceClassParameterName});")
.WriteClosingBracket(); .WriteClosingBracket();
}
return builder;
} }
} }
} }