Skip to content

Commit

Permalink
Add MappingTarget attribute to set the mapping target as the first pa…
Browse files Browse the repository at this point in the history
…rameter
  • Loading branch information
latonz committed Jul 4, 2024
1 parent 8cdb7a8 commit 12ca6ed
Show file tree
Hide file tree
Showing 20 changed files with 423 additions and 234 deletions.
2 changes: 1 addition & 1 deletion docs/docs/configuration/derived-type-mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: Map derived types and interfaces
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Mapperly supports interfaces and base types as mapping sources and targets, for both new instance and [existing target](./existing-target.md) mappings.
Mapperly supports interfaces and base types as mapping sources and targets, for both new instance and [existing target](./existing-target.mdx) mappings.
To do this, Mapperly needs to know which derived types exist.
This can be configured with the `MapDerivedTypeAttribute`:

Expand Down
76 changes: 0 additions & 76 deletions docs/docs/configuration/existing-target.md

This file was deleted.

114 changes: 114 additions & 0 deletions docs/docs/configuration/existing-target.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
sidebar_position: 9
description: Map to an existing target object
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Existing target object

If an existing object instance should be used as target, you can define the mapping method as void with the target as second parameter:

<Tabs>
<TabItem value="declaration" label="Declaration" default>
```csharp
[Mapper]
public partial class CarMapper
{
// highlight-start
public partial void UpdateCarDto(Car car, CarDto dto);
// highlight-end
}
```
</TabItem>
<TabItem value="usage" label="Usage">
```csharp
var mapper = new CarMapper();
var car = new Car { NumberOfSeats = 10, ... };
var dto = new CarDto();

mapper.UpdateCarDto(car, dto);
dto.NumberOfSeats.Should().Be(10);
```
</TabItem>
</Tabs>

## Merge objects

To merge two objects together, `AllowNullPropertyAssignment` can be set to `false`.
This ignores all properties on the source with a `null` value.

<Tabs>
<TabItem value="declaration" label="Declaration" default>
```csharp
// highlight-start
[Mapper(AllowNullPropertyAssignment = false)]
// highlight-end
static partial class FruitMapper
{
// highlight-start
public static partial void ApplyUpdate(FruitUpdate update, Fruit fruit);
// highlight-end
}

class Fruit { public required string Name { get; set; } public required string Color { get; set; } }
record FruitUpdate(string? Name, string? Color);
```
</TabItem>
<TabItem value="usage" label="Usage">
```csharp
FruitMapper.ApplyUpdate(myUpdateRequest, myFruit);
```
</TabItem>
<TabItem value="generated" label="Generated code" default>
```csharp
static partial class FruitMapper
{
public static partial void Update(global::FruitUpdate update, global::Fruit fruit)
{
if (update.Name != null)
{
fruit.Name = update.Name;
}
if (update.Color != null)
{
fruit.Color = update.Color;
}
}
}
```
</TabItem>
</Tabs>

See also [null value handling](./mapper.mdx#null-values).

The `MappingTarget` attribute allows setting the first method parameter as mapping target:

<Tabs>
<TabItem value="declaration" label="Declaration" default>

```csharp
// highlight-start
[Mapper(AllowNullPropertyAssignment = false)]
// highlight-end
static partial class FruitMapper
{
// highlight-start
public static partial void ApplyUpdate([MappingTarget] this Fruit fruit, FruitUpdate update);
// highlight-end
}

class Fruit { public required string Name { get; set; } public required string Color { get; set; } }
record FruitUpdate(string? Name, string? Color);
```

</TabItem>
<TabItem value="usage" label="Usage">
```csharp
myFruit.ApplyUpdate(myUpdateRequest);
```
</TabItem>
</Tabs>

See also [extension methods](./static-mappers.md).
2 changes: 1 addition & 1 deletion docs/docs/configuration/static-mappers.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Mapperly supports static mappers and extension methods:
[Mapper]
public static partial class CarMapper
{
public static partial CarDto CarToCarDto(this Car car);
public static partial CarDto ToCarDto(this Car car);

private static int TimeSpanToHours(TimeSpan t) => t.Hours;
}
Expand Down
10 changes: 10 additions & 0 deletions src/Riok.Mapperly.Abstractions/MappingTargetAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Diagnostics;

namespace Riok.Mapperly.Abstractions;

/// <summary>
/// Marks a given parameter as the mapping target.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
[Conditional("MAPPERLY_ABSTRACTIONS_SCOPE_RUNTIME")]
public sealed class MappingTargetAttribute : Attribute;
4 changes: 4 additions & 0 deletions src/Riok.Mapperly.Abstractions/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,7 @@ Riok.Mapperly.Abstractions.MapValueAttribute.MapValueAttribute(string![]! target
Riok.Mapperly.Abstractions.MapValueAttribute.Target.get -> System.Collections.Generic.IReadOnlyCollection<string!>!
Riok.Mapperly.Abstractions.MapValueAttribute.TargetFullName.get -> string!
Riok.Mapperly.Abstractions.MapValueAttribute.Value.get -> object?
Riok.Mapperly.Abstractions.MappingTargetAttribute
Riok.Mapperly.Abstractions.MappingTargetAttribute.MappingTargetAttribute() -> void
Riok.Mapperly.Abstractions.MapPropertyAttribute.MapPropertyAttribute(string! source, string![]! target) -> void
Riok.Mapperly.Abstractions.MapPropertyAttribute.MapPropertyAttribute(string![]! source, string! target) -> void
2 changes: 0 additions & 2 deletions src/Riok.Mapperly.Abstractions/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
#nullable enable
Riok.Mapperly.Abstractions.MapPropertyAttribute.MapPropertyAttribute(string! source, string![]! target) -> void
Riok.Mapperly.Abstractions.MapPropertyAttribute.MapPropertyAttribute(string![]! source, string! target) -> void
5 changes: 1 addition & 4 deletions src/Riok.Mapperly/Descriptors/SymbolAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ public bool CanAssign(ITypeSymbol sourceType, ITypeSymbol targetType)
&& (targetType.IsNullable() || !sourceType.IsNullable());
}

public MethodParameter? WrapOptionalMethodParameter(IParameterSymbol? symbol)
{
return symbol == null ? null : WrapMethodParameter(symbol);
}
public MethodParameter? WrapOptionalMethodParameter(IParameterSymbol? symbol) => symbol == null ? null : WrapMethodParameter(symbol);

public MethodParameter WrapMethodParameter(IParameterSymbol symbol) => new(symbol, UpgradeNullable(symbol.Type));

Expand Down
Loading

0 comments on commit 12ca6ed

Please sign in to comment.