using System;
using System.Collections.Generic;
using System.Linq;
namespace Quadarax.Foundation.Core.Mapper
{
///
/// Lightweight Object-to-Object Mapper.
///
public class Loom
{
///
/// Defines a new mapping function using a configuration-driven builder.
///
/// The source type.
/// The destination type.
///
public LoomBuilder Define()
where TFrom : class
where TTo : class, new()
{
return new LoomBuilder(this);
}
///
/// Defines a new mapping function.
///
/// The source type.
/// The destination type.
/// The mapping function.
public void Define(Action map)
{
if (!_maps.TryGetValue(typeof(TFrom), out Dictionary? inner))
{
inner = new Dictionary();
_maps[typeof(TFrom)] = inner;
}
inner[typeof(TTo)] = map;
}
///
/// Finds a mapping function.
///
/// The source type.
/// The destination type.
/// The mapping function for the given combination of types or a null reference when not defined.
public Action? Find()
{
if (!_maps.TryGetValue(typeof(TFrom), out Dictionary? inner)) return null;
if (!inner.TryGetValue(typeof(TTo), out var map)) return null;
return (Action) map;
}
///
/// Updates the destination object from the source using a mapping function.
///
/// The source type.
/// The destination type.
/// The source object.
/// The destination object.
public void Update(TFrom from, TTo to)
where TFrom : class
where TTo : class
{
if (from == null) throw new ArgumentNullException(nameof(from));
if (to == null) throw new ArgumentNullException(nameof(to));
Find()?.Invoke(from, to);
}
///
/// Creates a destination object from the source using a mapping function.
///
/// The source type.
/// The destination type.
/// The source object.
/// The destination object or a null reference in case is a null reference, too.
public TTo? Map(TFrom? from)
where TFrom : class
where TTo : class, new()
{
if (from == null) return null;
var to = new TTo();
Find()?.Invoke(from, to);
return to;
}
///
/// Creates a list of destination objects from source objects using a mapping function.
///
/// The source type.
/// The destination type.
/// The source objects.
/// The destination objects.
public List? Map(IEnumerable? from)
where TFrom : class
where TTo : class, new()
{
if (from == null) return null;
var map = Find();
return new List(from.Select(f => {
var to = new TTo();
map?.Invoke(f, to);
return to;
}));
}
///
/// Creates a list of destination objects from source objects using a mapping function.
///
/// The source type.
/// The destination type.
/// The source objects.
/// The destination objects.
public List? MapList(IEnumerable? from)
where TFrom : class
where TTo : class, new()
{
if (from == null) return null;
var map = Find();
return from.Select(f => New(map, f)).ToList();
}
///
/// Creates a list of destination objects from source objects using a mapping function.
///
/// The source type.
/// The destination type.
/// The source objects.
/// The destination objects.
public List? MapList(IQueryable? from)
where TFrom : class
where TTo : class, new()
{
if (from == null) return null;
var map = Find();
return from.Select(f => New(map, f)).ToList();
}
#region ------ Internals ------------------------------------------------------------------
private TTo New(Action? map, TFrom f)
where TFrom : class
where TTo : class, new()
{
var to = new TTo();
map?.Invoke(f, to);
return to;
}
///
/// Repository of all known mapping functions.
///
private readonly Dictionary> _maps = new();
#endregion
}
}