Skip to content

Commit

Permalink
feat: add MapProperty override, add tests and fix riok#450
Browse files Browse the repository at this point in the history
  • Loading branch information
TimothyMakkison committed May 21, 2023
1 parent 612ff4e commit 617fcd0
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public interface IMembersBuilderContext<out T>
IReadOnlyCollection<string> IgnoredSourceMemberNames { get; }

Dictionary<string, IMappableMember> TargetMembers { get; }
Dictionary<string, IMappableMember> IgnoredTargetMembers { get; }

Dictionary<string, List<MapPropertyAttribute>> MemberConfigsByRootTargetName { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ protected MembersMappingBuilderContext(MappingBuilderContext builderContext, T m
_unmappedSourceMemberNames = GetSourceMemberNames();
TargetMembers = GetTargetMembers();

var ignoredTargetMemberNames = GetIgnoredTargetMembers();
IgnoredSourceMemberNames = GetIgnoredSourceMembers();
var ignoredTargetMemberNames = GetIgnoredTargetMembers();

_ignoredUnmatchedSourceMemberNames = InitIgnoredUnmatchedProperties(IgnoredSourceMemberNames, _unmappedSourceMemberNames);
_ignoredUnmatchedTargetMemberNames = InitIgnoredUnmatchedProperties(ignoredTargetMemberNames, TargetMembers.Keys);

_unmappedSourceMemberNames.ExceptWith(IgnoredSourceMemberNames);
TargetMembers.RemoveRange(ignoredTargetMemberNames);
IgnoredTargetMembers = TargetMembers.ExtractRange(ignoredTargetMemberNames);
}

public MappingBuilderContext BuilderContext { get; }
Expand All @@ -44,6 +44,8 @@ protected MembersMappingBuilderContext(MappingBuilderContext builderContext, T m

public Dictionary<string, IMappableMember> TargetMembers { get; }

public Dictionary<string, IMappableMember> IgnoredTargetMembers { get; }

public Dictionary<string, List<MapPropertyAttribute>> MemberConfigsByRootTargetName { get; }

public void AddDiagnostics()
Expand Down Expand Up @@ -84,7 +86,7 @@ private IEnumerable<string> GetIgnoredObsoleteTargetMembers()

if (obsoleteAttribute.IgnoreObsoleteStrategy.HasFlag(IgnoreObsoleteMembersStrategy.Target))
{
return Mapping.SourceType
return Mapping.TargetType
.GetAccessibleMappableMembers()
.Where(x => x.MemberSymbol.HasAttribute(BuilderContext.Types.ObsoleteAttribute))
.Select(x => x.Name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ out var sourceMemberPath

BuildInitMemberMapping(ctx, targetMember, sourceMemberPath);
}

var initOnlyIgnoredTargetMembers = includeAllMembers
? ctx.IgnoredTargetMembers.Values.ToArray()
: ctx.IgnoredTargetMembers.Values.Where(x => x.CanOnlySetViaInitializer()).ToArray();
foreach (var targetMember in initOnlyIgnoredTargetMembers)
{
ctx.IgnoredTargetMembers.Remove(targetMember.Name);

if (ctx.MemberConfigsByRootTargetName.Remove(targetMember.Name, out var memberConfigs))
{
BuildInitMemberMapping(ctx, targetMember, memberConfigs);
}
}
}

private static void BuildInitMemberMapping(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ out var sourceMemberPath
}
}

foreach (var targetMember in ctx.IgnoredTargetMembers.Values)
{
if (ctx.MemberConfigsByRootTargetName.Remove(targetMember.Name, out var memberConfigs))
{
// add all configured mappings
// order by target path count to map less nested items first (otherwise they would overwrite all others)
// eg. target.A = source.B should be mapped before target.A.Id = source.B.Id
foreach (var config in memberConfigs.OrderBy(x => x.Target.Count))
{
BuildMemberAssignmentMapping(ctx, config);
}
}
}

ctx.AddDiagnostics();
}

Expand Down
15 changes: 15 additions & 0 deletions src/Riok.Mapperly/Helpers/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ public static void RemoveRange<TKey, TValue>(this IDictionary<TKey, TValue> dict
}
}

public static Dictionary<TKey, TValue> ExtractRange<TKey, TValue>(this IDictionary<TKey, TValue> dict, IEnumerable<TKey> keys)
{
var removedItems = new Dictionary<TKey, TValue>();
foreach (var key in keys)
{
if (dict.TryGetValue(key, out var value))
{
dict.Remove(key);
removedItems.Add(key, value);
}
}

return removedItems;
}

public static TValue? GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key)
{
dict.TryGetValue(key, out var value);
Expand Down
78 changes: 78 additions & 0 deletions test/Riok.Mapperly.Tests/Mapping/IgnoreObsoleteTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,82 @@ public void MethodAttributeOverridesClassAttribute()
"""
);
}

[Fact]
public void MapPropertyOverridesIgnoreObsoleteBoth()
{
var source = TestSourceBuilder.MapperWithBodyAndTypes(
"""
[MapProperty("Ignored", "Ignored")]
[MapperIgnoreObsoleteMembers]
partial B Map(A source);
""",
_classA,
_classB
);

TestHelper
.GenerateMapper(source, TestHelperOptions.AllowInfoDiagnostics)
.Should()
.HaveSingleMethodBody(
"""
var target = new global::B();
target.Value = source.Value;
target.Ignored = source.Ignored;
return target;
"""
);
}

[Fact]
public void MapPropertyOverridesIgnoreObsoleteSource()
{
var source = TestSourceBuilder.MapperWithBodyAndTypes(
"""
[MapProperty("Ignored", "Ignored")]
[MapperIgnoreObsoleteMembers(IgnoreObsoleteMembersStrategy.Source)]
partial B Map(A source);
""",
_classA,
_classB
);

TestHelper
.GenerateMapper(source, TestHelperOptions.AllowInfoDiagnostics)
.Should()
.HaveSingleMethodBody(
"""
var target = new global::B();
target.Value = source.Value;
target.Ignored = source.Ignored;
return target;
"""
);
}

[Fact]
public void MapPropertyOverridesIgnoreObsoleteTarget()
{
var source = TestSourceBuilder.MapperWithBodyAndTypes(
"""
[MapProperty("Ignored", "Ignored")]
[MapperIgnoreObsoleteMembers(IgnoreObsoleteMembersStrategy.Target)]
partial B Map(A source);
""",
_classA,
_classB
);

TestHelper
.GenerateMapper(source, TestHelperOptions.AllowInfoDiagnostics)
.Should()
.HaveSingleMethodBody(
"""
var target = new global::B();
target.Value = source.Value;
target.Ignored = source.Ignored;
return target;
"""
);
}
}

0 comments on commit 617fcd0

Please sign in to comment.