Skip to content

Commit

Permalink
huge refactoring
Browse files Browse the repository at this point in the history
- all associations have one or more marker interfaces
- mapper builder builds reader based on it's on logic
  • Loading branch information
maksimkim committed Aug 30, 2013
1 parent 1e82ac2 commit 6f591b5
Show file tree
Hide file tree
Showing 38 changed files with 1,107 additions and 696 deletions.
29 changes: 16 additions & 13 deletions src/EntityFunctors/Associations/CollectionAssociation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,32 @@
using System.Linq.Expressions;
using Extensions;

public class CollectionAssociation<TSource, TTarget> : CollectionAssociationBase<TSource, TTarget>
public class CollectionAssociation<TSource, TSourceItem, TTarget, TTargetItem>
: CollectionAssociationBase<TSource, TSourceItem, TTarget, TTargetItem>, IConvertionAssociation
where TSource : class
where TTarget : class, new()
{
public LambdaExpression Converter { get; private set; }
public ConverterInfo SourceConverter
{
get
{
throw new InvalidOperationException();
}
}

public ConverterInfo TargetConverter { get; private set; }

public CollectionAssociation(PropertyPart source, PropertyPart target, LambdaExpression converter)
public CollectionAssociation(Expression<Func<TSource, IEnumerable<TSourceItem>>> source, Expression<Func<TTarget, IEnumerable<TTargetItem>>> target, Expression<Func<TSourceItem, TTargetItem>> converter)
: base(source, target)
{
Contract.Assert(converter != null);
Contract.Assert(converter.Parameters.Count == 1);
Contract.Assert(converter.Parameters[0].Type == source.Property.PropertyType.GetItemType());
Contract.Assert(converter.ReturnType == target.Property.PropertyType.GetItemType());

Converter = converter;
}

public override IEnumerable<TypeMapKey> ChildMapKeys
{
get { yield break;}
TargetConverter = new ConverterInfo(converter);
}

protected override LambdaExpression CreateSelector(Type @from, Type to, ParameterExpression expands, IMappingRegistry registry)
{
return Converter;
return TargetConverter.Expression;
}
}
}
94 changes: 43 additions & 51 deletions src/EntityFunctors/Associations/CollectionAssociationBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,40 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Cfg;
using Extensions;
using Fluent;

public abstract class CollectionAssociationBase<TSource, TTarget> : IExpandable, IMappingAssociation
public abstract class CollectionAssociationBase<TSource, TSourceItem, TTarget, TTargetItem>
: IMappingAssociation, ICollectionAssociation, IExpandable
where TSource : class
where TTarget : class, new()
{
private static readonly MethodInfo ToArray;

private static readonly MethodInfo Select;

public PropertyPart Source { get; private set; }

public PropertyPart Target { get; private set; }
public string Key { get; private set; }

public MappingDirection Direction
{
get { return MappingDirection.Read; }
}

protected string Expand { get; set; }
public LambdaExpression Source { get; private set; }

public LambdaExpression Target { get; private set; }

public Type SourceItemType
{
get { return typeof(TSourceItem); }
}

public Type TargetItemType
{
get { return typeof(TTargetItem); }
}

public bool Expand { get; private set; }

static CollectionAssociationBase()
{
Expand All @@ -35,89 +50,66 @@ static CollectionAssociationBase()
Select = ((MethodCallExpression)((MethodCallExpression)exp.Body).Arguments[0]).Method.GetGenericMethodDefinition();
}

protected CollectionAssociationBase(PropertyPart source, PropertyPart target)
protected CollectionAssociationBase(
Expression<Func<TSource, IEnumerable<TSourceItem>>> source,
Expression<Func<TTarget, IEnumerable<TTargetItem>>> target
)
{
Contract.Assert(source != null);
Contract.Assert(target != null);

var propTarget = target.Property;

if (!(propTarget.PropertyType.IsGenericType && propTarget.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
throw new InvalidOperationException(
string.Format(
"Collection mapping supports only IEnumerable<T> type for target property {0} but found {1}",
typeof(TTarget).Name + "." + propTarget.Name,
propTarget.PropertyType
)
);
PropertyInfo prop;
Contract.Assert(source.Body.TryGetProperty(out prop));
Contract.Assert(target.Body.TryGetProperty(out prop));

Source = source;
Target = target;

Source = source;
Key = Target.GetProperty().GetName();
}

public virtual Expression BuildMapper(ParameterExpression @from, ParameterExpression to, ParameterExpression propertyKeys, IMappingRegistry registry)
{
if (!(@from.Type == typeof(TSource) && to.Type == typeof(TTarget)))
return Expression.Empty();

var propFrom = Expression.Property(@from, Source.Property);
var propTo = Expression.Property(to, Target.Property);

var itemTypeFrom = Source.Property.PropertyType.GetItemType();
var itemTypeTo = Target.Property.PropertyType.GetItemType();
var donor = Source.Apply(@from);
var acceptor = Target.Apply(to);

Expression mapper = Expression.Assign(
propTo,
acceptor,
Expression.Condition(
propFrom.CreateCheckForDefault(),
Target.Property.PropertyType.GetDefaultExpression(),
donor.CreateCheckForDefault(),
Target.ReturnType.GetDefaultExpression(),
Expression.Convert(
Expression.Call(
ToArray.MakeGenericMethod(itemTypeTo),
ToArray.MakeGenericMethod(TargetItemType),
Expression.Call(
Select.MakeGenericMethod(itemTypeFrom, itemTypeTo),
propFrom,
CreateSelector(itemTypeFrom, itemTypeTo, propertyKeys, registry)
Select.MakeGenericMethod(SourceItemType, TargetItemType),
donor,
CreateSelector(SourceItemType, TargetItemType, propertyKeys, registry)
)
),
Target.Property.PropertyType
Target.ReturnType
)
)
);

if (propertyKeys != null && !string.IsNullOrWhiteSpace(Expand))
if (propertyKeys != null && Expand)
mapper =
Expression.IfThen(
propertyKeys.CreateContains(Expression.Constant(Expand, typeof(string))),
propertyKeys.CreateContains(Expression.Constant(Key, typeof(string))),
mapper
);

return mapper;
}

public Expression Build(Expression arg)
{
return Expression.Property(arg, Source.Property);
}

public PropertyInfo TargetProperty
{
get { return Target.Property; }
}

public Expression Rewrite(Expression original, Expression replacement)
{
return Expression.Property(replacement, Source.Property);
}

public abstract IEnumerable<TypeMapKey> ChildMapKeys { get; }

protected abstract LambdaExpression CreateSelector(Type @from, Type to, ParameterExpression expands, IMappingRegistry registry);

public void Expandable()
{
Expand = Config.ReflectionOptimizer.GetName(Target.Property);
Expand = true;
}
}
}
30 changes: 14 additions & 16 deletions src/EntityFunctors/Associations/ComponentCollectionAssociation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,21 @@
using System.Linq.Expressions;
using Extensions;

public class ComponentCollectionAssociation<TSource, TTarget> : CollectionAssociationBase<TSource, TTarget>
public class ComponentCollectionAssociation<TSource, TSourceItem, TTarget, TTargetItem>
: CollectionAssociationBase<TSource, TSourceItem, TTarget, TTargetItem>, IComponentAssociation
where TSource : class
where TSourceItem : class
where TTarget : class, new()
where TTargetItem: class, new()
{
public ComponentCollectionAssociation(PropertyPart source, PropertyPart target)
:base(source, target)
{

}
public TypeMapKey ComponentKey { get; private set; }

public override IEnumerable<TypeMapKey> ChildMapKeys
public ComponentCollectionAssociation(
Expression<Func<TSource, IEnumerable<TSourceItem>>> source,
Expression<Func<TTarget, IEnumerable<TTargetItem>>> target)
: base(source, target)
{
get
{
yield return new TypeMapKey(
Source.Property.PropertyType.GetItemType(),
Target.Property.PropertyType.GetItemType()
);
}
ComponentKey = new TypeMapKey(SourceItemType, TargetItemType);
}

protected override LambdaExpression CreateSelector(Type @from, Type to, ParameterExpression expands, IMappingRegistry registry)
Expand All @@ -44,8 +42,8 @@ protected override LambdaExpression CreateSelector(Type @from, Type to, Paramete
if (mapper == null)
throw new InvalidOperationException(string.Format(
"Component collection registration mapping {0} <--> {1} requires mapping for types {2} <--> {3} that wasn't found",
typeof(TSource).Name + "." + Source.Property.Name,
typeof(TTarget).Name + "." + Target.Property.Name,
typeof(TSource).Name + "." + Source.GetProperty().Name,
typeof(TTarget).Name + "." + Target.GetProperty().Name,
@from,
to
));
Expand Down
Loading

0 comments on commit 6f591b5

Please sign in to comment.