Skip to content

Commit

Permalink
Merge pull request #43 from BlaiseD/master
Browse files Browse the repository at this point in the history
Code cleanup for VisitMember.
  • Loading branch information
BlaiseD authored Sep 2, 2019
2 parents 4f422cf + 7a619f9 commit 8f40b61
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 103 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<Authors>Jimmy Bogard</Authors>
<LangVersion>latest</LangVersion>
<VersionPrefix>3.0.2-preview01</VersionPrefix>
<VersionPrefix>3.0.2-preview02</VersionPrefix>
<WarningsAsErrors>true</WarningsAsErrors>
<NoWarn>$(NoWarn);1701;1702;1591</NoWarn>
</PropertyGroup>
Expand Down
71 changes: 28 additions & 43 deletions src/AutoMapper.Extensions.ExpressionMapping/MapIncludesVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,60 +23,45 @@ protected override Expression VisitMember(MemberExpression node)
return base.VisitMember(node);

InfoDictionary.Add(parameterExpression, TypeMappings);
string sourcePath = node.GetPropertyFullName();
Expression baseParentExpr = node.GetBaseOfMemberExpression();
Expression visitedParentExpr = this.Visit(baseParentExpr);
Type sType = baseParentExpr.Type;
Type dType = visitedParentExpr.Type;
return GetMappedMemberExpression(node.GetBaseOfMemberExpression(), new List<PropertyMapInfo>());

var propertyMapInfoList = new List<PropertyMapInfo>();
FindDestinationFullName(sType, dType, sourcePath, propertyMapInfoList);
string fullName;

if (propertyMapInfoList.Any(x => x.CustomExpression != null))//CustomExpression takes precedence over DestinationPropertyInfo
Expression GetMappedMemberExpression(Expression parentExpression, List<PropertyMapInfo> propertyMapInfoList)
{
var last = propertyMapInfoList.Last(x => x.CustomExpression != null);
var beforeCustExpression = propertyMapInfoList.Aggregate(new List<PropertyMapInfo>(), (list, next) =>
{
if (propertyMapInfoList.IndexOf(next) < propertyMapInfoList.IndexOf(last))
list.Add(next);
return list;
});
Expression mappedParentExpression = this.Visit(parentExpression);
FindDestinationFullName(parentExpression.Type, mappedParentExpression.Type, node.GetPropertyFullName(), propertyMapInfoList);

var afterCustExpression = propertyMapInfoList.Aggregate(new List<PropertyMapInfo>(), (list, next) =>
if (propertyMapInfoList.Any(x => x.CustomExpression != null))//CustomExpression takes precedence over DestinationPropertyInfo
{
if (propertyMapInfoList.IndexOf(next) > propertyMapInfoList.IndexOf(last))
list.Add(next);
return list;
});


fullName = BuildFullName(beforeCustExpression);
return GetMemberExpression
(
new FindMemberExpressionsVisitor(mappedParentExpression),
GetMemberExpressionFromCustomExpression
(
propertyMapInfoList,
propertyMapInfoList.Last(x => x.CustomExpression != null),
mappedParentExpression
)
);
}

var visitor = new PrependParentNameVisitor
return GetExpressionForInclude
(
last.CustomExpression.Parameters[0].Type/*Parent type of current property*/,
fullName,
visitedParentExpr
GetMemberExpressionFromMemberMaps
(
BuildFullName(propertyMapInfoList),
mappedParentExpression
)
);
}

var ex = propertyMapInfoList[propertyMapInfoList.Count - 1] != last
? visitor.Visit(last.CustomExpression.Body.MemberAccesses(afterCustExpression))
: visitor.Visit(last.CustomExpression.Body);

var v = new FindMemberExpressionsVisitor(visitedParentExpr);
v.Visit(ex);
Expression GetExpressionForInclude(MemberExpression memberExpression)
=> memberExpression.Type.IsLiteralType() ? memberExpression.Expression : memberExpression;

return v.Result;
}
fullName = BuildFullName(propertyMapInfoList);
var me = ExpressionHelpers.MemberAccesses(fullName, InfoDictionary[parameterExpression].NewParameter);
if (me.Expression.NodeType == ExpressionType.MemberAccess && me.Type.IsLiteralType())
MemberExpression GetMemberExpression(FindMemberExpressionsVisitor visitor, Expression mappedExpression)
{
return me.Expression;
visitor.Visit(mappedExpression);
return visitor.Result;
}

return me;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ protected override Expression VisitMember(MemberExpression node)
? sourcePath
: string.Concat(ParentFullName, ".", sourcePath);

var me = ExpressionHelpers.MemberAccesses(fullName, NewParameter);

return me;
return ExpressionHelpers.MemberAccesses(fullName, NewParameter);
}
}
}
122 changes: 78 additions & 44 deletions src/AutoMapper.Extensions.ExpressionMapping/XpressionMapperVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,56 +45,81 @@ protected override Expression VisitMember(MemberExpression node)
return base.VisitMember(node);

InfoDictionary.Add(parameterExpression, TypeMappings);
return GetMappedMemberExpression(node.GetBaseOfMemberExpression(), new List<PropertyMapInfo>());

string sourcePath = node.GetPropertyFullName();
Expression baseParentExpr = node.GetBaseOfMemberExpression();
Expression visitedParentExpr = this.Visit(baseParentExpr);
Type sType = baseParentExpr.Type;
Type dType = visitedParentExpr.Type;

var propertyMapInfoList = new List<PropertyMapInfo>();
FindDestinationFullName(sType, dType, sourcePath, propertyMapInfoList);
string fullName;

if (propertyMapInfoList.Any(x => x.CustomExpression != null))
Expression GetMappedMemberExpression(Expression parentExpression, List<PropertyMapInfo> propertyMapInfoList)
{
var last = propertyMapInfoList.Last(x => x.CustomExpression != null);
var beforeCustExpression = propertyMapInfoList.Aggregate(new List<PropertyMapInfo>(), (list, next) =>
{
if (propertyMapInfoList.IndexOf(next) < propertyMapInfoList.IndexOf(last))
list.Add(next);
return list;
});
Expression mappedParentExpression = this.Visit(parentExpression);
FindDestinationFullName(parentExpression.Type, mappedParentExpression.Type, node.GetPropertyFullName(), propertyMapInfoList);

var afterCustExpression = propertyMapInfoList.Aggregate(new List<PropertyMapInfo>(), (list, next) =>
if (propertyMapInfoList.Any(x => x.CustomExpression != null))
{
if (propertyMapInfoList.IndexOf(next) > propertyMapInfoList.IndexOf(last))
list.Add(next);
return list;
});

fullName = BuildFullName(beforeCustExpression);
var visitor = new PrependParentNameVisitor
(
last.CustomExpression.Parameters[0].Type/*Parent type of current property*/,
fullName,
visitedParentExpr
);
var fromCustomExpression = GetMemberExpressionFromCustomExpression
(
propertyMapInfoList,
propertyMapInfoList.Last(x => x.CustomExpression != null),
mappedParentExpression
);

this.TypeMappings.AddTypeMapping(ConfigurationProvider, node.Type, fromCustomExpression.Type);
return fromCustomExpression;
}

var ex = propertyMapInfoList[propertyMapInfoList.Count - 1] != last
? visitor.Visit(last.CustomExpression.Body.MemberAccesses(afterCustExpression))
: visitor.Visit(last.CustomExpression.Body);
var memberExpression = GetMemberExpressionFromMemberMaps(BuildFullName(propertyMapInfoList), mappedParentExpression);
this.TypeMappings.AddTypeMapping(ConfigurationProvider, node.Type, memberExpression.Type);

this.TypeMappings.AddTypeMapping(ConfigurationProvider, node.Type, ex.Type);
return ex;
return memberExpression;
}
fullName = BuildFullName(propertyMapInfoList);
var me = ExpressionHelpers.MemberAccesses(fullName, visitedParentExpr);
}

protected MemberExpression GetMemberExpressionFromMemberMaps(string fullName, Expression visitedParentExpr)
=> ExpressionHelpers.MemberAccesses(fullName, visitedParentExpr);

this.TypeMappings.AddTypeMapping(ConfigurationProvider, node.Type, me.Type);
return me;
private Expression GetMemberExpressionFromCustomExpression(PropertyMapInfo lastWithCustExpression,
PropertyMapInfo lastInList,
List<PropertyMapInfo> beforeCustExpression,
List<PropertyMapInfo> afterCustExpression,
Expression visitedParentExpr)
{
return PrependParentMemberExpression
(
new PrependParentNameVisitor
(
lastWithCustExpression.CustomExpression.Parameters[0].Type/*Parent type of current property*/,
BuildFullName(beforeCustExpression),
visitedParentExpr
)
);

Expression PrependParentMemberExpression(PrependParentNameVisitor visitor)
=> visitor.Visit
(
lastInList != lastWithCustExpression
? lastWithCustExpression.CustomExpression.Body.MemberAccesses(afterCustExpression)
: lastWithCustExpression.CustomExpression.Body
);
}

protected Expression GetMemberExpressionFromCustomExpression(List<PropertyMapInfo> propertyMapInfoList, PropertyMapInfo lastWithCustExpression, Expression mappedParentExpr)
=> GetMemberExpressionFromCustomExpression
(
lastWithCustExpression,
propertyMapInfoList.Last(),
propertyMapInfoList.Aggregate(new List<PropertyMapInfo>(), (list, next) =>
{
if (propertyMapInfoList.IndexOf(next) < propertyMapInfoList.IndexOf(lastWithCustExpression))
list.Add(next);
return list;
}),
propertyMapInfoList.Aggregate(new List<PropertyMapInfo>(), (list, next) =>
{
if (propertyMapInfoList.IndexOf(next) > propertyMapInfoList.IndexOf(lastWithCustExpression))
list.Add(next);
return list;
}),
mappedParentExpr
);

protected override Expression VisitLambda<T>(Expression<T> node)
{
var ex = this.Visit(node.Body);
Expand Down Expand Up @@ -148,10 +173,19 @@ protected override Expression VisitUnary(UnaryExpression node)

Expression DoVisitUnary(Expression updated)
{
if (updated != node.Operand)
return node.Update(updated);

return node;
if (this.TypeMappings.TryGetValue(node.Type, out Type mappedType))
return Expression.MakeUnary
(
node.NodeType,
updated != node.Operand
? updated
: node.Operand,
mappedType
);

return updated != node.Operand
? node.Update(updated)
: base.VisitUnary(node);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,20 +607,20 @@ public void Shoud_convert_type_changes()
destItem.DestValue.ShouldBe(sourceItem.SrcValue);
}

[Fact(Skip="Conventions not available like this.")]
public void Shoud_work_with_conventions()
{
//var mapper = new MapperConfiguration(cfg => cfg.AddConditionalObjectMapper()
// .Where((s, d) => s.Name == d.Name + "Model" || s.Name + "Model" == d.Name)).CreateMapper();
//[Fact(Skip="Conventions not available like this.")]
//public void Shoud_work_with_conventions()
//{
// //var mapper = new MapperConfiguration(cfg => cfg.AddConditionalObjectMapper()
// // .Where((s, d) => s.Name == d.Name + "Model" || s.Name + "Model" == d.Name)).CreateMapper();


//IQueryable<Destination> result = _source.AsQueryable()
// .UseAsDataSource(Mapper).For<Destination>()
// .Where(s => s.DestValue > 6);
// //IQueryable<Destination> result = _source.AsQueryable()
// // .UseAsDataSource(Mapper).For<Destination>()
// // .Where(s => s.DestValue > 6);

//result.Count().ShouldBe(1);
//result.Any(s => s.DestValue > 6).ShouldBeTrue();
}
// //result.Count().ShouldBe(1);
// //result.Any(s => s.DestValue > 6).ShouldBeTrue();
//}

private static IMapper SetupAutoMapper()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ public void Can_map_expression_when_mapped_when_members_parent_is_a_method()
emp.Events.First(e => e.EventType.Equals("Stop")).EventDate < DateTime.Today.AddYears(-1);

//Act
Expression<Func<EmployeeEntity, bool>> mappedFilter = mapper.MapExpression<Expression<Func<EmployeeEntity, bool>>>(filter);
Expression<Func<EmployeeEntity, bool>> mappedFilter = mapper.MapExpression<Expression<Func<EmployeeEntity, bool>>>(filter);
List<EmployeeEntity> res = empEntity.AsQueryable().Where(mappedFilter).ToList();

//Assert
Expand Down

0 comments on commit 8f40b61

Please sign in to comment.