diff --git a/README.md b/README.md index 6084dc6..5757607 100644 --- a/README.md +++ b/README.md @@ -74,10 +74,9 @@ Follows a common-sense semantic versioning pattern: ```bash dotnet add package CoreMap ``` +# 🚀 Usage -## 🚀 Usage - -### 1. Create Entities +## 1. Create Entities ```csharp public record ArticleEntity @@ -92,10 +91,11 @@ public record AuthorEntity { public Guid Id { get; init; } public string Name { get; init; } = default!; - } ``` -### 2. Create Responses (DTOs) + +## 2. Create Responses (DTOs) + ```csharp internal record ArticleResponse { @@ -104,6 +104,7 @@ internal record ArticleResponse public string Description { get; init; } = default!; public AuthorResponse Author { get; init; } = default!; } + internal class AuthorResponse { public Guid Id { get; init; } @@ -111,7 +112,8 @@ internal class AuthorResponse public string Description { get; init; } = default!; } ``` -### 3. Create Handlers + +# 3. Create Mapping Handlers ```csharp internal class AuthorResponseToEntityMap : ICoreMapHandler @@ -122,6 +124,7 @@ internal class AuthorResponseToEntityMap : ICoreMapHandler { public ArticleEntity Handler(ArticleResponse data, ICoreMap alsoMap) => new ArticleEntity() @@ -131,74 +134,57 @@ internal class ArticleResponseToEntityMap : ICoreMapHandler(data.Author) }; - } ``` -### 4. Register Services -In your Startup or whereever you define your dependency injection: +# 4. Register Services + ```csharp - public static IServiceCollection AddServices(IServiceCollection services){ - // For Assembly Scanned Registration - services.AddCoreMap(o => { }, new Type[]{ - typeof(Startup) - }); +public static IServiceCollection AddServices(IServiceCollection services) +{ + // Assembly-scanned registration + services.AddCoreMap(o => { }, new Type[] + { + typeof(Startup) + }); + + // Or manual registration + services.AddCoreMap(o => { }); + services.AddScoped, ArticleResponseToEntityMap>(); + services.AddScoped, AuthorResponseToEntityMap>(); + + return services; +} +``` - // For Manually Registration - services.AddCoreMap(o => { }); - services.AddScoped, ArticleResponseToEntityMap>(); - services.AddScoped, AuthorResponseToEntityMap>(); - return service; - } +# 5. Mapping Examples +## Fluent Mapping (Preferred) +### Map a single object + +```csharp +ArticleEntity item = coreMap.Map(response).To(); ``` -### 4. Use Mapping -Example: +### Map a collection + ```csharp -private ArticleEntity Item { get; set; } = default!; -protected override void OnInitialized(IServiceProvider serviceP) -{ - var coreMap = serviceP.GetRequiredService(); - var response = new ArticleResponse() - { - Description = "A description", - Title = "A Title", - Id = Guid.NewGuid(), - Author = new AuthorResponse() - { - Id = Guid.NewGuid(), - Title = "Maksim Shimshon" - } - }; +ICollection entities = + coreMap.MapEach(responses).To(); +``` - Item = coreMap.MapTo(responses); -} +## Traditional Mapping (Still Supported) + +### Map a single object + +```csharp +ArticleEntity item = coreMap.MapTo(response); ``` -Map a collection: +### Map a collection + ```csharp -private ArticleEntity Item { get; set; } = default!; -protected override void OnInitialized(IServiceProvider serviceP) -{ - var coreMap = serviceP.GetRequiredService(); - var response = new ArticleResponse() - { - Description = "A description", - Title = "A Title", - Id = Guid.NewGuid(), - Author = new AuthorResponse() - { - Id = Guid.NewGuid(), - Title = "Maksim Shimshon" - } - }; - List responses = new() - { - response with { }, - response with{ } - }; - ICollection entities = coreMap.MapEachTo(responses); -} +ICollection entities = + coreMap.MapEachTo(responses); ``` diff --git a/RELEASES.md b/RELEASES.md index c03fda9..99ab8dd 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,18 @@ README: https://github.com/mshimshon/CoreMap +# v1.1.0 +## New Features +- Added Fluent Mapping support for both single and collection mappings +- Introduced Map() builder for fluent single-object mapping +- Introduced MapEach() builder for fluent collection mapping + +## Improvements +- CoreMapper internally updated to support fluent builders +- Infrastructure prepared for future fluent extensions + +## Unchanged +- Traditional MapTo and MapEachTo methods remain fully supported + # v1.0.0 - Added Support for .NET 10 diff --git a/src/CoreMap/CoreMap.csproj b/src/CoreMap/CoreMap.csproj index f9fb490..8ad42c7 100644 --- a/src/CoreMap/CoreMap.csproj +++ b/src/CoreMap/CoreMap.csproj @@ -2,7 +2,7 @@ net10.0;net6.0;net8.0;netstandard2.1;netstandard2.0; - 10 + 14 enable enable true @@ -17,7 +17,7 @@ RELEASES.md https://github.com/mshimshon/CoreMap/tree/main mapping, object-mapper, dependency-injection, clean-architecture, dotnet, csharp, async, manual-mapping, design-patterns, software-architecture, lightweight - 1.0.0 + 1.1.0 LICENSE True icon.png diff --git a/src/CoreMap/CoreMapConfiguration.cs b/src/CoreMap/CoreMapConfiguration.cs index 5f53b1b..9a01b30 100644 --- a/src/CoreMap/CoreMapConfiguration.cs +++ b/src/CoreMap/CoreMapConfiguration.cs @@ -4,4 +4,5 @@ namespace CoreMap; public class CoreMapConfiguration { public ServiceScope Scope { get; set; } = ServiceScope.Scoped; + } diff --git a/src/CoreMap/Engine/CoreMapBuilder.cs b/src/CoreMap/Engine/CoreMapBuilder.cs new file mode 100644 index 0000000..0f3bc78 --- /dev/null +++ b/src/CoreMap/Engine/CoreMapBuilder.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CoreMap.Engine; + +internal class CoreMapBuilder : ICoreMapBuilder where TOrigin : class +{ + private readonly TOrigin _origin; + private readonly ICoreMap _coreMap; + + public CoreMapBuilder(TOrigin origin, ICoreMap coreMap) + { + _origin = origin; + _coreMap = coreMap; + } + + public TDestination To() where TDestination : class + => _coreMap.MapTo(_origin); +} diff --git a/src/CoreMap/Engine/CoreMapListBuilder.cs b/src/CoreMap/Engine/CoreMapListBuilder.cs new file mode 100644 index 0000000..7d409fc --- /dev/null +++ b/src/CoreMap/Engine/CoreMapListBuilder.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CoreMap.Engine; + +internal class CoreMapListBuilder : ICoreMapListBuilder where TOrigin : class +{ + private readonly ICollection _origin; + private readonly ICoreMap _coreMap; + + public CoreMapListBuilder(ICollection origin, ICoreMap coreMap) + { + _origin = origin; + _coreMap = coreMap; + } + + public ICollection To() where TDestination : class + => _coreMap.MapEachTo(_origin); +} diff --git a/src/CoreMap/Engine/CoreMapper.cs b/src/CoreMap/Engine/CoreMapper.cs index 4a19ece..2d64fa6 100644 --- a/src/CoreMap/Engine/CoreMapper.cs +++ b/src/CoreMap/Engine/CoreMapper.cs @@ -20,11 +20,21 @@ public TDestination MapTo(TOrigin origin) public ICollection MapEachTo(ICollection origins) => origins.Select(MapTo).ToList(); - - private ICoreMapHandler GetService() { return _serviceProvider.GetRequiredService>(); } + public ICoreMapBuilder Map(TOrigin origin) where TOrigin : class + { + var builder = new CoreMapBuilder(origin, this); + return builder; + } + + public ICoreMapListBuilder MapEach(ICollection origins) + where TOrigin : class + { + var builder = new CoreMapListBuilder(origins, this); + return builder; + } } diff --git a/src/CoreMap/ICoreMap.cs b/src/CoreMap/ICoreMap.cs index 4c9dda4..9580761 100644 --- a/src/CoreMap/ICoreMap.cs +++ b/src/CoreMap/ICoreMap.cs @@ -1,6 +1,12 @@ namespace CoreMap; public interface ICoreMap { + + ICoreMapBuilder Map(TOrigin origin) + where TOrigin : class; + TDestination MapTo(TOrigin origin); ICollection MapEachTo(ICollection origins); + ICoreMapListBuilder MapEach(ICollection origins) + where TOrigin : class; } diff --git a/src/CoreMap/ICoreMapBuilder.cs b/src/CoreMap/ICoreMapBuilder.cs new file mode 100644 index 0000000..aecce56 --- /dev/null +++ b/src/CoreMap/ICoreMapBuilder.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CoreMap; + +public interface ICoreMapBuilder +{ + TDestination To() where TDestination : class; + + +} diff --git a/src/CoreMap/ICoreMapListBuilder.cs b/src/CoreMap/ICoreMapListBuilder.cs new file mode 100644 index 0000000..f87ed69 --- /dev/null +++ b/src/CoreMap/ICoreMapListBuilder.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CoreMap; + +public interface ICoreMapListBuilder +{ + ICollection To() where TDestination : class; + + +} diff --git a/tests/CoreMap.Tests/MappingTests.cs b/tests/CoreMap.Tests/MappingTests.cs index 4c19708..417efc8 100644 --- a/tests/CoreMap.Tests/MappingTests.cs +++ b/tests/CoreMap.Tests/MappingTests.cs @@ -28,6 +28,28 @@ public void RequestShouldProperlyConvert() Assert.Equal(entity.WrittenBy.Id, createRequest.AuthorId); } + [Fact] + public void RequestShouldProperlyConvert_UsingFluent() + { + var coreMap = ServiceProvider.GetRequiredService(); + var entity = new ArticleEntity() + { + Description = "A description", + Title = "A Title", + Id = Guid.NewGuid(), + WrittenBy = new AuthorEntity() + { + Id = Guid.NewGuid(), + Name = "Maksim Shimshon" + } + }; + + var createRequest2 = coreMap.Map(entity).To(); + Assert.Equal(entity.Title, createRequest2.Title); + Assert.Equal(entity.Description, createRequest2.Description); + Assert.Equal(entity.WrittenBy.Id, createRequest2.AuthorId); + } + [Fact] public void ArrayConverter_ShouldConvertAll() { @@ -58,5 +80,39 @@ response with{ } Assert.Equal(response.Author.Title, p.WrittenBy.Name); Assert.Equal(response.Author.Id, p.WrittenBy.Id); }); + + } + + [Fact] + public void ArrayConverter_ShouldConvertAll_UsingFluent() + { + var coreMap = ServiceProvider.GetRequiredService(); + var response = new ArticleResponse() + { + Description = "A description", + Title = "A Title", + Id = Guid.NewGuid(), + Author = new AuthorResponse() + { + Id = Guid.NewGuid(), + Title = "Maksim Shimshon" + } + }; + List responses = new() + { + response with { }, + response with{ } + }; + + + ICollection entities = coreMap.MapEach(responses).To(); + Assert.All(entities, p => + { + Assert.Equal(response.Title, p.Title); + Assert.Equal(response.Description, p.Description); + Assert.Equal(response.Id, p.Id); + Assert.Equal(response.Author.Title, p.WrittenBy.Name); + Assert.Equal(response.Author.Id, p.WrittenBy.Id); + }); } }