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 } }