Skip to content

Commit

Permalink
fix: resolve user implemented mappings correctly in queryable project…
Browse files Browse the repository at this point in the history
…ions
  • Loading branch information
latonz committed Sep 8, 2023
1 parent 18e5dc9 commit c218c37
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ conversionType is not MappingConversionType.EnumToString and not MappingConversi
if (_inlineExpressionMappings.Find(sourceType, targetType) is { } mapping)
return mapping;

// user implemented mappings are also taken into account
// this works as long as the user implemented methods
// User implemented mappings are also taken into account.
// This works as long as the user implemented methods
// follow the expression tree limitations:
// https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/expression-trees/#limitations
if (_parentContext.FindMapping(sourceType, targetType) is UserImplementedMethodMapping userMapping)
Expand Down Expand Up @@ -100,7 +100,7 @@ conversionType is not MappingConversionType.EnumToString and not MappingConversi
{
sourceType = sourceType.UpgradeNullable();
targetType = targetType.UpgradeNullable();
var mapping = _inlineExpressionMappings.Find(sourceType, targetType);
var mapping = FindMapping(sourceType, targetType);
if (mapping != null)
return mapping;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,7 @@ public TestObjectDtoProjection(int ctorValue)
public TimeOnly DateTimeValueTargetTimeOnly { get; set; }

public TestObjectDtoManuallyMappedProjection? ManuallyMapped { get; set; }

public List<TestEnum> ManuallyMappedList { get; set; } = new();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public static partial class ProjectionMapper
return new TestObjectDtoManuallyMappedProjection(100) { StringValue = str, };
}

private static TestEnum MapManual(TestObjectProjectionEnumValue source) => source.Value;

[MapDerivedType(typeof(TestObjectProjectionTypeA), typeof(TestObjectDtoProjectionTypeA))]
[MapDerivedType(typeof(TestObjectProjectionTypeB), typeof(TestObjectDtoProjectionTypeB))]
private static partial TestObjectDtoProjectionBaseType MapDerived(TestObjectProjectionBaseType source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace Riok.Mapperly.IntegrationTests.Models
{
public class TestObjectProjection
{
public int Id { get; set; }

public int CtorValue { get; set; }

public int IntValue { get; set; }
Expand Down Expand Up @@ -61,6 +63,8 @@ public class TestObjectProjection

public DateTime DateTimeValueTargetTimeOnly { get; set; }

public String ManuallyMapped { get; set; } = "fooBar";
public string ManuallyMapped { get; set; } = "fooBar";

public List<TestObjectProjectionEnumValue> ManuallyMappedList { get; set; } = new();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Riok.Mapperly.IntegrationTests.Models
{
public class TestObjectProjectionEnumValue
{
public int Id { get; set; }

public int OtherValue { get; set; }

public TestEnum Value { get; set; }
}
}
12 changes: 10 additions & 2 deletions test/Riok.Mapperly.IntegrationTests/ProjectionMapperTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Riok.Mapperly.IntegrationTests.Helpers;
Expand Down Expand Up @@ -90,7 +91,7 @@ private TestObjectProjection CreateObject()
EnumName = TestEnum.Value10,
EnumReverseStringValue = nameof(TestEnum.Value10),
EnumValue = TestEnum.Value20,
IntValue = 100,
Id = 100,
EnumRawValue = TestEnum.Value30,
EnumStringValue = TestEnum.Value10,
Flattening = new IdObject { IdValue = 10 },
Expand All @@ -113,6 +114,12 @@ private TestObjectProjection CreateObject()
EnumReverseStringValue = nameof(TestEnum.Value10),
EnumValue = TestEnum.Value20,
},
ManuallyMapped = "fooBar5",
ManuallyMappedList = new List<TestObjectProjectionEnumValue>
{
new TestObjectProjectionEnumValue { Value = TestEnum.Value10 },
new TestObjectProjectionEnumValue { Value = TestEnum.Value20 },
},
};
}

Expand All @@ -126,9 +133,10 @@ public ProjectionDbContext(DbContextOptions options)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TestObjectProjection>().HasKey(p => p.IntValue);
modelBuilder.Entity<TestObjectProjection>().HasKey(p => p.Id);
modelBuilder.Entity<TestObjectProjection>().HasOne(p => p.RecursiveObject);
modelBuilder.Entity<TestObjectProjection>().HasOne(p => p.SubObject);
modelBuilder.Entity<TestObjectProjection>().HasMany(p => p.ManuallyMappedList);

modelBuilder.Entity<IdObject>().HasKey(p => p.IdValue);
modelBuilder.Entity<InheritanceSubObject>().HasKey(p => p.SubIntValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
END, CASE
WHEN "t"."IntValue" IS NOT NULL THEN "t"."IntValue"
ELSE 0
END, "t"."IntValue" IS NOT NULL, "t"."IntValue", "t0"."IntValue" IS NOT NULL, "t0"."IntValue", COALESCE("o"."StringNullableTargetNotNullable", ''), "o0"."IntValue", "o0"."CtorValue", "o0"."DateTimeValueTargetDateOnly", "o0"."DateTimeValueTargetTimeOnly", "o0"."EnumName", "o0"."EnumRawValue", "o0"."EnumReverseStringValue", "o0"."EnumStringValue", "o0"."EnumValue", "o0"."FlatteningIdValue", "o0"."IgnoredIntValue", "o0"."IgnoredStringValue", "o0"."IntInitOnlyValue", "o0"."ManuallyMapped", "o0"."NestedNullableIntValue", "o0"."NestedNullableTargetNotNullableIntValue", "o0"."NullableFlatteningIdValue", "o0"."NullableUnflatteningIdValue", "o0"."RecursiveObjectIntValue", "o0"."RenamedStringValue", "o0"."RequiredValue", "o0"."StringNullableTargetNotNullable", "o0"."StringValue", "o0"."SubObjectSubIntValue", "o0"."UnflatteningIdValue", "i0"."IdValue", "i1"."SubIntValue", "t1"."IntValue", "t1"."TestObjectProjectionIntValue", "t2"."IntValue", CAST("o"."EnumValue" AS INTEGER), CAST("o"."EnumName" AS INTEGER), CAST("o"."EnumRawValue" AS INTEGER), "o"."EnumStringValue", "o"."EnumReverseStringValue", "i1"."SubIntValue" IS NOT NULL, "i1"."BaseIntValue", "o"."DateTimeValueTargetDateOnly", "o"."DateTimeValueTargetTimeOnly", "o"."ManuallyMapped"
END, "t"."IntValue" IS NOT NULL, "t"."IntValue", "t0"."IntValue" IS NOT NULL, "t0"."IntValue", COALESCE("o"."StringNullableTargetNotNullable", ''), "o0"."Id", "o0"."CtorValue", "o0"."DateTimeValueTargetDateOnly", "o0"."DateTimeValueTargetTimeOnly", "o0"."EnumName", "o0"."EnumRawValue", "o0"."EnumReverseStringValue", "o0"."EnumStringValue", "o0"."EnumValue", "o0"."FlatteningIdValue", "o0"."IgnoredIntValue", "o0"."IgnoredStringValue", "o0"."IntInitOnlyValue", "o0"."IntValue", "o0"."ManuallyMapped", "o0"."NestedNullableIntValue", "o0"."NestedNullableTargetNotNullableIntValue", "o0"."NullableFlatteningIdValue", "o0"."NullableUnflatteningIdValue", "o0"."RecursiveObjectId", "o0"."RenamedStringValue", "o0"."RequiredValue", "o0"."StringNullableTargetNotNullable", "o0"."StringValue", "o0"."SubObjectSubIntValue", "o0"."UnflatteningIdValue", "o"."Id", "i0"."IdValue", "i1"."SubIntValue", "t1"."IntValue", "t1"."TestObjectProjectionId", "t2"."IntValue", CAST("o"."EnumValue" AS INTEGER), CAST("o"."EnumName" AS INTEGER), CAST("o"."EnumRawValue" AS INTEGER), "o"."EnumStringValue", "o"."EnumReverseStringValue", "i1"."SubIntValue" IS NOT NULL, "i1"."BaseIntValue", "o"."DateTimeValueTargetDateOnly", "o"."DateTimeValueTargetTimeOnly", "o"."ManuallyMapped", "t3"."Id", "t3"."OtherValue", "t3"."TestObjectProjectionId", "t3"."Value"
FROM "Objects" AS "o"
INNER JOIN "IdObject" AS "i" ON "o"."FlatteningIdValue" = "i"."IdValue"
LEFT JOIN "IdObject" AS "i0" ON "o"."NullableFlatteningIdValue" = "i0"."IdValue"
LEFT JOIN "TestObjectNested" AS "t" ON "o"."NestedNullableIntValue" = "t"."IntValue"
LEFT JOIN "TestObjectNested" AS "t0" ON "o"."NestedNullableTargetNotNullableIntValue" = "t0"."IntValue"
LEFT JOIN "Objects" AS "o0" ON "o"."IntValue" = "o0"."RecursiveObjectIntValue"
LEFT JOIN "Objects" AS "o0" ON "o"."Id" = "o0"."RecursiveObjectId"
LEFT JOIN "InheritanceSubObject" AS "i1" ON "o"."SubObjectSubIntValue" = "i1"."SubIntValue"
LEFT JOIN "TestObjectNested" AS "t1" ON "o"."IntValue" = "t1"."TestObjectProjectionIntValue"
LEFT JOIN "TestObjectNested" AS "t2" ON "o"."IntValue" = "t2"."TestObjectProjectionIntValue"
ORDER BY "o"."IntValue", "i"."IdValue", "i0"."IdValue", "t"."IntValue", "t0"."IntValue", "o0"."IntValue", "i1"."SubIntValue", "t1"."IntValue"
LEFT JOIN "TestObjectNested" AS "t1" ON "o"."Id" = "t1"."TestObjectProjectionId"
LEFT JOIN "TestObjectNested" AS "t2" ON "o"."Id" = "t2"."TestObjectProjectionId"
LEFT JOIN "TestObjectProjectionEnumValue" AS "t3" ON "o"."Id" = "t3"."TestObjectProjectionId"
ORDER BY "o"."Id", "i"."IdValue", "i0"."IdValue", "t"."IntValue", "t0"."IntValue", "o0"."Id", "i1"."SubIntValue", "t1"."IntValue", "t2"."IntValue"
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[
{
IntValue: 1,
RequiredValue: -1,
StringValue: ,
RenamedStringValue2: ,
Expand All @@ -9,8 +8,8 @@
NestedNullableTargetNotNullable: {},
StringNullableTargetNotNullable: ,
SourceTargetSameObjectType: {
Id: 100,
CtorValue: 2,
IntValue: 100,
IntInitOnlyValue: 4,
RequiredValue: 10,
StringValue: fooBar3,
Expand All @@ -24,7 +23,7 @@
UnflatteningIdValue: 7,
StringNullableTargetNotNullable: fooBar,
RecursiveObject: {
IntValue: 1,
Id: 1,
RequiredValue: -1,
StringValue: ,
RenamedStringValue: ,
Expand All @@ -49,7 +48,17 @@
IgnoredIntValue: 3,
DateTimeValueTargetDateOnly: 2018-11-29 10:11:12,
DateTimeValueTargetTimeOnly: 2018-11-29 10:11:12,
ManuallyMapped: fooBar
ManuallyMapped: fooBar5,
ManuallyMappedList: [
{
Id: 1,
Value: Value10
},
{
Id: 2,
Value: Value20
}
]
},
EnumValue: DtoValue2,
EnumName: 10,
Expand All @@ -62,7 +71,6 @@
},
{
CtorValue: 2,
IntValue: 100,
IntInitOnlyValue: 4,
RequiredValue: 10,
StringValue: fooBar3,
Expand All @@ -84,7 +92,11 @@
DateTimeValueTargetTimeOnly: 10:11 AM,
ManuallyMapped: {
MagicIntValue: 100,
StringValue: fooBar
}
StringValue: fooBar5
},
ManuallyMappedList: [
Value10,
Value20
]
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public static partial class ProjectionMapper
DateTimeValueTargetDateOnly = global::System.DateOnly.FromDateTime(x.DateTimeValueTargetDateOnly),
DateTimeValueTargetTimeOnly = global::System.TimeOnly.FromDateTime(x.DateTimeValueTargetTimeOnly),
ManuallyMapped = MapManual(x.ManuallyMapped),
ManuallyMappedList = global::System.Linq.Enumerable.ToList(global::System.Linq.Enumerable.Select(x.ManuallyMappedList, x1 => MapManual(x1))),
});
#nullable enable
}
Expand Down Expand Up @@ -107,6 +108,7 @@ public static partial class ProjectionMapper
target.DateTimeValueTargetDateOnly = global::System.DateOnly.FromDateTime(testObject.DateTimeValueTargetDateOnly);
target.DateTimeValueTargetTimeOnly = global::System.TimeOnly.FromDateTime(testObject.DateTimeValueTargetTimeOnly);
target.ManuallyMapped = MapManual(testObject.ManuallyMapped);
target.ManuallyMappedList = MapToList(testObject.ManuallyMappedList);
return target;
}

Expand Down Expand Up @@ -186,5 +188,15 @@ private static string MapToString(global::Riok.Mapperly.IntegrationTests.Models.
target.BaseIntValue = source.BaseIntValue;
return target;
}

private static global::System.Collections.Generic.List<global::Riok.Mapperly.IntegrationTests.Models.TestEnum> MapToList(global::System.Collections.Generic.List<global::Riok.Mapperly.IntegrationTests.Models.TestObjectProjectionEnumValue> source)
{
var target = new global::System.Collections.Generic.List<global::Riok.Mapperly.IntegrationTests.Models.TestEnum>(source.Count);
foreach (var item in source)
{
target.Add(MapManual(item));
}
return target;
}
}
}
36 changes: 36 additions & 0 deletions test/Riok.Mapperly.Tests/Mapping/QueryableProjectionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,42 @@ public Task ClassToClassWithConfigs()
return TestHelper.VerifyGenerator(source);
}

[Fact]
public Task RecordToRecordManualFlatteningInsideList()
{
var source = TestSourceBuilder.MapperWithBodyAndTypes(
"""
private partial System.Linq.IQueryable<B> Map(System.Linq.IQueryable<A> source);

private partial D Map(C source) => source.Value;
""",
"record A(Guid Id, List<C> Values);",
"record B(string Id, List<D> Values);",
"enum D(V1, V2, V3);",
"record C(D Value);"
);

return TestHelper.VerifyGenerator(source);
}

[Fact]
public Task RecordToRecordManualListMapping()
{
var source = TestSourceBuilder.MapperWithBodyAndTypes(
"""
private partial System.Linq.IQueryable<B> Map(System.Linq.IQueryable<A> source);

private partial List<D> Map(List<C> source) => source.Select(x => x.Value).ToList();
""",
"record A(Guid Id, List<C> Values);",
"record B(string Id, List<D> Values);",
"enum D(V1, V2, V3);",
"record C(D Value);"
);

return TestHelper.VerifyGenerator(source);
}

[Fact]
public Task ClassToClassWithUserImplemented()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//HintName: Mapper.g.cs
// <auto-generated />
#nullable enable
public partial class Mapper
{
private partial global::System.Linq.IQueryable<global::B> Map(global::System.Linq.IQueryable<global::A> source)
{
#nullable disable
return System.Linq.Queryable.Select(source, x => new global::B(x.Id.ToString(), global::System.Linq.Enumerable.ToList(global::System.Linq.Enumerable.Select(x.Values, x1 => Map(x1)))));
#nullable enable
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//HintName: Mapper.g.cs
// <auto-generated />
#nullable enable
public partial class Mapper
{
private partial global::System.Linq.IQueryable<global::B> Map(global::System.Linq.IQueryable<global::A> source)
{
#nullable disable
return System.Linq.Queryable.Select(source, x => new global::B(x.Id.ToString(), Map(x.Values)));
#nullable enable
}
}

0 comments on commit c218c37

Please sign in to comment.