From b5dc28e7de211e75713dd61f53cf0bf44a726423 Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 28 Oct 2023 06:06:11 +0500 Subject: [PATCH 1/8] add test --- ...MappingPrimitiveCustomMappingRegression.cs | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs diff --git a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs new file mode 100644 index 00000000..01b0820e --- /dev/null +++ b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs @@ -0,0 +1,116 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Shouldly; +using System; + +namespace Mapster.Tests +{ + [TestClass] + public class WhenMappingPrimitiveCustomMappingRegression + { + public void CustomMappingDateTimeToPrimitive() + { + TypeAdapterConfig + .NewConfig() + .MapWith(src => new DateTimeOffset(src).ToUnixTimeSeconds()); + + TypeAdapterConfig + .NewConfig() + .MapWith(src => src.ToShortDateString()); + + var _source = new DateTime(2023, 10, 27); + + var _resultToLong = _source.Adapt(); + var _resultToString = _source.Adapt(); + + + } + + /// + /// https://github.com/MapsterMapper/Mapster/issues/561 + /// + [TestMethod] + public void MappingToPrimitiveInsiderWithCustomMapping() + { + TypeAdapterConfig, string?> + .NewConfig() + .MapToTargetWith((source, target) => source.HasValue ? source.Value : target); + + var sourceNull = new Source561 { Name = new Optional561(null) }; + var target = new Source561 { Name = new Optional561("John") }.Adapt(); + + var TargetDestinationFromNull = new Target561() { Name = "Me" }; + var NullToupdateoptional = sourceNull.Adapt(TargetDestinationFromNull); + var _result = sourceNull.Adapt(target); + + target.Name.ShouldBe("John"); + NullToupdateoptional.Name.ShouldBe("Me"); + } + + /// + /// https://github.com/MapsterMapper/Mapster/issues/407 + /// + [TestMethod] + public void MappingDatetimeToLongWithCustomMapping() + { + TypeAdapterConfig + .NewConfig() + .MapWith(src => new DateTimeOffset(src).ToUnixTimeSeconds()); + + TypeAdapterConfig + .NewConfig() + .MapWith(src => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(src).Date); + + var emptySource = new Source407() { Time = DateTime.UtcNow.Date }; + var fromC1 = new DateTime(2023, 10, 27); + var fromC2 = new DateTimeOffset(new DateTime(2025, 11, 23)).ToUnixTimeSeconds(); + var c1 = new Source407 { Time = fromC1 }; + var c2 = new Destination407 { Time = fromC2 }; + + var _result = c1.Adapt(); // Work + var _resultLongtoDateTime = c2.Adapt(); + + _result.Time.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27)).ToUnixTimeSeconds()); // Work + _resultLongtoDateTime.Time.ShouldBe(new DateTime(2025, 11, 22).Date); // work but but it turns out to be a day less. Perhaps this is how it was intended + } + + } + + + #region TestClasses + + public class Source407 + { + public DateTime Time { get; set; } + } + + public class Destination407 + { + public long Time { get; set; } + } + + class Optional561 + { + public Optional561(T? value) + { + if (value != null) + HasValue = true; + + Value = value; + } + + public bool HasValue { get; } + public T? Value { get; } + } + + class Source561 + { + public Optional561 Name { get; set; } + } + + class Target561 + { + public string? Name { get; set; } + } + + #endregion TestClasses +} From 6215452c2c11d0d4bc33e61975db1eebea55b424 Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 28 Oct 2023 06:12:18 +0500 Subject: [PATCH 2/8] impliment in TypeAdaptSettings and TypeAdaptSetter --- src/Mapster/TypeAdapterSetter.cs | 10 ++++++++++ src/Mapster/TypeAdapterSettings.cs | 21 +++++++++++++++++++++ src/Mapster/Utils/ReflectionUtils.cs | 5 +++++ 3 files changed, 36 insertions(+) diff --git a/src/Mapster/TypeAdapterSetter.cs b/src/Mapster/TypeAdapterSetter.cs index 9215f375..c0bf07c4 100644 --- a/src/Mapster/TypeAdapterSetter.cs +++ b/src/Mapster/TypeAdapterSetter.cs @@ -611,6 +611,11 @@ public TypeAdapterSetter MapWith(Expression MapToTargetWith(Expression Set(nameof(GenerateMapper), value); } + public bool? MapWithToPrimitive + { + get => Get(nameof(MapWithToPrimitive)); + set => Set(nameof(MapWithToPrimitive), value); + } + + /// + /// Not implemented + /// + public bool? MapToPrimitive + { + get => Get(nameof(MapToPrimitive)); + set => Set(nameof(MapToPrimitive), value); + } + + public bool? MapToTargetPrimitive + { + get => Get(nameof(MapToTargetPrimitive)); + set => Set(nameof(MapToTargetPrimitive), value); + } + public List> ShouldMapMember { get => Get(nameof(ShouldMapMember), () => new List>()); diff --git a/src/Mapster/Utils/ReflectionUtils.cs b/src/Mapster/Utils/ReflectionUtils.cs index fe44e790..1de6e7ae 100644 --- a/src/Mapster/Utils/ReflectionUtils.cs +++ b/src/Mapster/Utils/ReflectionUtils.cs @@ -36,6 +36,11 @@ public static Type GetTypeInfo(this Type type) } #endif + public static bool IsMapsterPrimitive(this Type type) + { + return _primitiveTypes.TryGetValue(type, out var primitiveType) || type == typeof(string); + } + public static bool IsNullable(this Type type) { return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); From 6ebac66afad98aeeb79b7dff6efd95c74edc98bc Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 28 Oct 2023 06:26:47 +0500 Subject: [PATCH 3/8] Implimentation in BaseAdapter and PrimitiveAdapter --- src/Mapster/Adapters/BaseAdapter.cs | 26 ++++++++++++++++++++++++ src/Mapster/Adapters/PrimitiveAdapter.cs | 18 ++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/Mapster/Adapters/BaseAdapter.cs b/src/Mapster/Adapters/BaseAdapter.cs index b7b6fc67..92e9990a 100644 --- a/src/Mapster/Adapters/BaseAdapter.cs +++ b/src/Mapster/Adapters/BaseAdapter.cs @@ -85,6 +85,32 @@ protected virtual Expression CreateExpressionBody(Expression source, Expression? if (CheckExplicitMapping && arg.Context.Config.RequireExplicitMapping && !arg.ExplicitMapping) throw new InvalidOperationException("Implicit mapping is not allowed (check GlobalSettings.RequireExplicitMapping) and no configuration exists"); + #region CustomMappingPrimitiveImplimentation + + if (arg.Settings.MapToTargetPrimitive == true) + { + Expression dest; + + if (destination == null) + { + dest = arg.DestinationType.CreateDefault(); + } + else + dest = destination; + + var customConvert = arg.Context.Config.CreateMapToTargetInvokeExpressionBody(source.Type, arg.DestinationType, source, dest); + + arg.MapType = MapType.MapToTarget; + return customConvert; + } + + if (arg.Settings.MapWithToPrimitive == true) + { + return arg.Context.Config.CreateMapInvokeExpressionBody(source.Type, arg.DestinationType, source); + } + + #endregion CustomMappingPrimitiveImplimentation + var oldMaxDepth = arg.Context.MaxDepth; var oldDepth = arg.Context.Depth; try diff --git a/src/Mapster/Adapters/PrimitiveAdapter.cs b/src/Mapster/Adapters/PrimitiveAdapter.cs index 2a407a89..cfc7c809 100644 --- a/src/Mapster/Adapters/PrimitiveAdapter.cs +++ b/src/Mapster/Adapters/PrimitiveAdapter.cs @@ -18,6 +18,24 @@ protected override bool CanMap(PreCompileArgument arg) protected override Expression CreateExpressionBody(Expression source, Expression? destination, CompileArgument arg) { + + if (arg.Settings.MapToTargetPrimitive == true) + { + Expression dest; + + if (destination == null) + { + dest = arg.DestinationType.CreateDefault(); + } + else + dest = destination; + + var customConvert = arg.Context.Config.CreateMapToTargetInvokeExpressionBody(source.Type, arg.DestinationType, source, dest); + + arg.MapType = MapType.MapToTarget; + return customConvert; + } + Expression convert = source; var sourceType = arg.SourceType; var destinationType = arg.DestinationType; From d7f40a12f59b2cffa3efb280500a4cf2def3b1d0 Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 28 Oct 2023 06:35:42 +0500 Subject: [PATCH 4/8] refactoring tests --- .../WhenMappingPrimitiveCustomMappingRegression.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs index 01b0820e..d1df5b80 100644 --- a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs +++ b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs @@ -7,6 +7,7 @@ namespace Mapster.Tests [TestClass] public class WhenMappingPrimitiveCustomMappingRegression { + [TestMethod] public void CustomMappingDateTimeToPrimitive() { TypeAdapterConfig @@ -22,7 +23,9 @@ public void CustomMappingDateTimeToPrimitive() var _resultToLong = _source.Adapt(); var _resultToString = _source.Adapt(); - + _resultToLong.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27)).ToUnixTimeSeconds()); + _resultToString.ShouldNotBe(_source.ToString()); + _resultToString.ShouldBe(_source.ToShortDateString()); } /// From 0eccadcbb316e767d3c720bbb8e1c66c750c2378 Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 28 Oct 2023 08:27:10 +0500 Subject: [PATCH 5/8] fix date --- .../WhenMappingPrimitiveCustomMappingRegression.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs index d1df5b80..477b445d 100644 --- a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs +++ b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs @@ -65,7 +65,7 @@ public void MappingDatetimeToLongWithCustomMapping() var emptySource = new Source407() { Time = DateTime.UtcNow.Date }; var fromC1 = new DateTime(2023, 10, 27); - var fromC2 = new DateTimeOffset(new DateTime(2025, 11, 23)).ToUnixTimeSeconds(); + var fromC2 = new DateTimeOffset(new DateTime(2025, 11, 23,0,0,0,DateTimeKind.Utc)).ToUnixTimeSeconds(); var c1 = new Source407 { Time = fromC1 }; var c2 = new Destination407 { Time = fromC2 }; @@ -73,7 +73,7 @@ public void MappingDatetimeToLongWithCustomMapping() var _resultLongtoDateTime = c2.Adapt(); _result.Time.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27)).ToUnixTimeSeconds()); // Work - _resultLongtoDateTime.Time.ShouldBe(new DateTime(2025, 11, 22).Date); // work but but it turns out to be a day less. Perhaps this is how it was intended + _resultLongtoDateTime.Time.ShouldBe(new DateTime(2025, 11, 23).Date); // work but but it turns out to be a day less. Perhaps this is how it was intended } } From af1f374f9635007ea4a738bdbf6ffd1a7271fe7e Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 28 Oct 2023 08:34:29 +0500 Subject: [PATCH 6/8] date all fix --- .../WhenMappingPrimitiveCustomMappingRegression.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs index 477b445d..f97383a9 100644 --- a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs +++ b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs @@ -64,7 +64,7 @@ public void MappingDatetimeToLongWithCustomMapping() .MapWith(src => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(src).Date); var emptySource = new Source407() { Time = DateTime.UtcNow.Date }; - var fromC1 = new DateTime(2023, 10, 27); + var fromC1 = new DateTime(2023, 10, 27,0,0,0,DateTimeKind.Utc); var fromC2 = new DateTimeOffset(new DateTime(2025, 11, 23,0,0,0,DateTimeKind.Utc)).ToUnixTimeSeconds(); var c1 = new Source407 { Time = fromC1 }; var c2 = new Destination407 { Time = fromC2 }; @@ -72,7 +72,7 @@ public void MappingDatetimeToLongWithCustomMapping() var _result = c1.Adapt(); // Work var _resultLongtoDateTime = c2.Adapt(); - _result.Time.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27)).ToUnixTimeSeconds()); // Work + _result.Time.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27, 0, 0, 0, DateTimeKind.Utc)).ToUnixTimeSeconds()); // Work _resultLongtoDateTime.Time.ShouldBe(new DateTime(2025, 11, 23).Date); // work but but it turns out to be a day less. Perhaps this is how it was intended } From 00bc359f1e786a6bf11a6f9c8b704030ff81b77f Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 28 Oct 2023 08:45:00 +0500 Subject: [PATCH 7/8] final refactoring tests and drop comments --- .../WhenMappingPrimitiveCustomMappingRegression.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs index f97383a9..c2f17261 100644 --- a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs +++ b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs @@ -18,12 +18,12 @@ public void CustomMappingDateTimeToPrimitive() .NewConfig() .MapWith(src => src.ToShortDateString()); - var _source = new DateTime(2023, 10, 27); + var _source = new DateTime(2023, 10, 27, 0, 0, 0, DateTimeKind.Utc); var _resultToLong = _source.Adapt(); var _resultToString = _source.Adapt(); - _resultToLong.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27)).ToUnixTimeSeconds()); + _resultToLong.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27, 0, 0, 0, DateTimeKind.Utc)).ToUnixTimeSeconds()); _resultToString.ShouldNotBe(_source.ToString()); _resultToString.ShouldBe(_source.ToShortDateString()); } @@ -65,15 +65,15 @@ public void MappingDatetimeToLongWithCustomMapping() var emptySource = new Source407() { Time = DateTime.UtcNow.Date }; var fromC1 = new DateTime(2023, 10, 27,0,0,0,DateTimeKind.Utc); - var fromC2 = new DateTimeOffset(new DateTime(2025, 11, 23,0,0,0,DateTimeKind.Utc)).ToUnixTimeSeconds(); + var fromC2 = new DateTimeOffset(new DateTime(2025, 11, 23, 0, 0, 0, DateTimeKind.Utc)).ToUnixTimeSeconds(); var c1 = new Source407 { Time = fromC1 }; var c2 = new Destination407 { Time = fromC2 }; var _result = c1.Adapt(); // Work var _resultLongtoDateTime = c2.Adapt(); - _result.Time.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27, 0, 0, 0, DateTimeKind.Utc)).ToUnixTimeSeconds()); // Work - _resultLongtoDateTime.Time.ShouldBe(new DateTime(2025, 11, 23).Date); // work but but it turns out to be a day less. Perhaps this is how it was intended + _result.Time.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27, 0, 0, 0, DateTimeKind.Utc)).ToUnixTimeSeconds()); + _resultLongtoDateTime.Time.ShouldBe(new DateTime(2025, 11, 23).Date); } } From 50ade18843e39315aff0dff349321318a9738919 Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 28 Oct 2023 09:22:49 +0500 Subject: [PATCH 8/8] Add Projection test --- ...MappingPrimitiveCustomMappingRegression.cs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs index c2f17261..d694ac67 100644 --- a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs +++ b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs @@ -1,6 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Shouldly; using System; +using System.Collections.Generic; +using System.Linq; namespace Mapster.Tests { @@ -69,13 +71,39 @@ public void MappingDatetimeToLongWithCustomMapping() var c1 = new Source407 { Time = fromC1 }; var c2 = new Destination407 { Time = fromC2 }; - var _result = c1.Adapt(); // Work + var _result = c1.Adapt(); var _resultLongtoDateTime = c2.Adapt(); _result.Time.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27, 0, 0, 0, DateTimeKind.Utc)).ToUnixTimeSeconds()); _resultLongtoDateTime.Time.ShouldBe(new DateTime(2025, 11, 23).Date); } + /// + /// https://github.com/MapsterMapper/Mapster/issues/407 + /// + [TestMethod] + public void CustomMappingPrimitiveToProjection() + { + TypeAdapterConfig + .NewConfig() + .MapWith(src => new DateTimeOffset(src).ToUnixTimeSeconds()); + + TypeAdapterConfig + .NewConfig() + .MapWith(src => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(src).Date); + + var _sourceList = new List(); + _sourceList.Add(new Source407 { Time = new DateTime(2023, 10, 27, 0, 0, 0, DateTimeKind.Utc) }); + var _fromC2List = new List(); + _fromC2List.Add(new Destination407 { Time = new DateTimeOffset(new DateTime(2025, 11, 23, 0, 0, 0, DateTimeKind.Utc)).ToUnixTimeSeconds() }); + + var _resultProjectionDateTimeTolong = _sourceList.AsQueryable().ProjectToType().ToList(); + var _resultProjectionLongToDateTime = _fromC2List.AsQueryable().ProjectToType().ToList(); + + _resultProjectionDateTimeTolong[0].Time.ShouldBe(new DateTimeOffset(new DateTime(2023, 10, 27, 0, 0, 0, DateTimeKind.Utc)).ToUnixTimeSeconds()); + _resultProjectionLongToDateTime[0].Time.ShouldBe(new DateTime(2025, 11, 23).Date); + } + }