Skip to content

Commit

Permalink
feat: ✨ migrate customers-service to use mapperly for mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
mehdihadeli committed Aug 21, 2024
1 parent 3d025d9 commit f216b18
Show file tree
Hide file tree
Showing 70 changed files with 494 additions and 540 deletions.
3 changes: 1 addition & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ Thanks a bunch for supporting me!
- ✔️ **[`Microsoft.AspNetCore.Authentication.JwtBearer`](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer)** - Handling Jwt Authentication and authorization in .Net Core
- ✔️ **[`NSubstitute`](https://github.com/nsubstitute/NSubstitute)** - A friendly substitute for .NET mocking libraries.
- ✔️ **[`StyleCopAnalyzers`](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)** - An implementation of StyleCop rules using the .NET Compiler Platform
- ✔️ **[`AutoMapper`](https://github.com/AutoMapper/AutoMapper)** - Convention-based object-object mapper in .NET.
- ✔️ **[`Hellang.Middleware.ProblemDetails`](https://github.com/khellang/Middleware/tree/master/src/ProblemDetails)** - A middleware for handling exception in .Net Core
- ✔️ **[`Mapperly`](https://github.com/riok/mapperly)** - A .NET source generator for generating object mappings, No runtime reflection.
- ✔️ **[`IdGen`](https://github.com/RobThree/IdGen)** - Twitter Snowflake-alike ID generator for .Net

## Setup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ Task<IPageList<TResult>> GetByPageFilter<TResult, TSortKey>(
CancellationToken cancellationToken = default
)
where TResult : class;

Task<IPageList<TResult>> GetByPageFilter<TResult, TSortKey>(
IPageRequest pageRequest,
Func<IQueryable<TEntity>, IQueryable<TResult>> projectionFunc,
Expression<Func<TEntity, TSortKey>> sortExpression,
Expression<Func<TEntity, bool>>? predicate = null,
CancellationToken cancellationToken = default
)
where TResult : class;
}

public interface IWriteRepository<TEntity, in TId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@ public interface IHttpCommand<TRequest>
TRequest Request { get; init; }
HttpContext HttpContext { get; init; }
ICommandBus CommandBus { get; init; }
IMapper Mapper { get; init; }
CancellationToken CancellationToken { get; init; }
}

public interface IHttpCommand
{
HttpContext HttpContext { get; init; }
ICommandBus CommandBus { get; init; }
IMapper Mapper { get; init; }
CancellationToken CancellationToken { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,5 @@ public interface IHttpQuery
{
HttpContext HttpContext { get; init; }
IQueryBus QueryBus { get; init; }
IMapper Mapper { get; init; }
CancellationToken CancellationToken { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace BuildingBlocks.Core.Extensions;

// we should not operation related to Ef or Mongo here and we should design as general with IQueryable to work with any providers
// we should not relate to Ef or Mongo here, and we should design as general with IQueryable to work with any providers
public static class QueryableExtensions
{
public static async Task<IPageList<TEntity>> ApplyPagingAsync<TEntity>(
Expand All @@ -30,7 +30,7 @@ CancellationToken cancellationToken
// https://github.com/Biarity/Sieve/issues/34#issuecomment-403817573
var result = sieveProcessor.Apply(sieveModel, queryable, applyPagination: false);
var total = result.Count();
result = sieveProcessor.Apply(sieveModel, queryable, applyFiltering: false, applySorting: false); // Only
result = sieveProcessor.Apply(sieveModel, queryable, applyFiltering: false, applySorting: false);

var items = await result.ToAsyncEnumerable().ToListAsync(cancellationToken: cancellationToken);

Expand All @@ -40,8 +40,38 @@ CancellationToken cancellationToken
public static async Task<IPageList<TResult>> ApplyPagingAsync<TEntity, TResult>(
this IQueryable<TEntity> queryable,
IPageRequest pageRequest,
ISieveProcessor sieveProcessor,
IConfigurationProvider configurationProvider,
CancellationToken cancellationToken
)
where TEntity : class
where TResult : class
{
var sieveModel = new SieveModel
{
PageSize = pageRequest.PageSize,
Page = pageRequest.PageNumber,
Sorts = pageRequest.SortOrder,
Filters = pageRequest.Filters
};

// https://github.com/Biarity/Sieve/issues/34#issuecomment-403817573
var result = sieveProcessor.Apply(sieveModel, queryable, applyPagination: false);
var total = result.Count();
result = sieveProcessor.Apply(sieveModel, queryable, applyFiltering: false, applySorting: false); // Only applies pagination

var projectedQuery = result.ProjectTo<TResult>(configurationProvider);

var items = await projectedQuery.ToAsyncEnumerable().ToListAsync(cancellationToken: cancellationToken);

return PageList<TResult>.Create(items.AsReadOnly(), pageRequest.PageNumber, pageRequest.PageSize, total);
}

public static async Task<IPageList<TResult>> ApplyPagingAsync<TEntity, TResult>(
this IQueryable<TEntity> queryable,
IPageRequest pageRequest,
ISieveProcessor sieveProcessor,
Func<IQueryable<TEntity>, IQueryable<TResult>> projectionFunc,
CancellationToken cancellationToken
)
where TEntity : class
Expand All @@ -60,14 +90,44 @@ CancellationToken cancellationToken
var total = result.Count();
result = sieveProcessor.Apply(sieveModel, queryable, applyFiltering: false, applySorting: false); // Only applies pagination

var items = await result
.ProjectTo<TResult>(configurationProvider)
.ToAsyncEnumerable()
.ToListAsync(cancellationToken: cancellationToken);
var projectedQuery = projectionFunc(result);

var items = await projectedQuery.ToAsyncEnumerable().ToListAsync(cancellationToken: cancellationToken);

return PageList<TResult>.Create(items.AsReadOnly(), pageRequest.PageNumber, pageRequest.PageSize, total);
}

public static async Task<IPageList<TResult>> ApplyPagingAsync<TEntity, TResult, TSortKey>(
this IQueryable<TEntity> collection,
IPageRequest pageRequest,
ISieveProcessor sieveProcessor,
Func<IQueryable<TEntity>, IQueryable<TResult>> projectionFunc,
Expression<Func<TEntity, bool>>? predicate = null,
Expression<Func<TEntity, TSortKey>>? sortExpression = null,
CancellationToken cancellationToken = default
)
where TEntity : class
where TResult : class
{
IQueryable<TEntity> query = collection;
if (predicate is not null)
{
query = query.Where(predicate);
}

if (sortExpression is not null)
{
query = query.OrderByDescending(sortExpression);
}

return await query.ApplyPagingAsync<TEntity, TResult>(
pageRequest,
sieveProcessor,
projectionFunc,
cancellationToken
);
}

public static async Task<IPageList<TResult>> ApplyPagingAsync<TEntity, TResult>(
this IQueryable<TEntity> queryable,
IPageRequest pageRequest,
Expand Down Expand Up @@ -124,8 +184,8 @@ public static async Task<IPageList<TResult>> ApplyPagingAsync<TEntity, TResult,

return await query.ApplyPagingAsync<TEntity, TResult>(
pageRequest,
configuration,
sieveProcessor,
configuration,
cancellationToken
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,25 @@ public async Task<IPageList<TResult>> GetByPageFilter<TResult, TSortKey>(
);
}

public async Task<IPageList<TResult>> GetByPageFilter<TResult, TSortKey>(
IPageRequest pageRequest,
Func<IQueryable<TEntity>, IQueryable<TResult>> projectionFunc,
Expression<Func<TEntity, TSortKey>> sortExpression,
Expression<Func<TEntity, bool>>? predicate = null,
CancellationToken cancellationToken = default
)
where TResult : class
{
return await DbSet.ApplyPagingAsync<TEntity, TResult, TSortKey>(
pageRequest,
sieveProcessor,
projectionFunc,
predicate,
sortExpression,
cancellationToken
);
}

public async Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default)
{
entity.NotBeNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,27 @@ public async Task<IPageList<TResult>> GetByPageFilter<TResult, TSortKey>(
);
}

public async Task<IPageList<TResult>> GetByPageFilter<TResult, TSortKey>(
IPageRequest pageRequest,
Func<IQueryable<TEntity>, IQueryable<TResult>> projectionFunc,
Expression<Func<TEntity, TSortKey>> sortExpression,
Expression<Func<TEntity, bool>>? predicate = null,
CancellationToken cancellationToken = default
)
where TResult : class
{
return await DbSet
.AsQueryable()
.ApplyPagingAsync<TEntity, TResult, TSortKey>(
pageRequest,
_sieveProcessor,
projectionFunc,
predicate,
sortExpression,
cancellationToken
);
}

public Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default)
{
Context.AddCommand(async () =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using BuildingBlocks.Abstractions.Commands;
using BuildingBlocks.Abstractions.Queries;
using BuildingBlocks.Abstractions.Web.MinimalApi;
using BuildingBlocks.Web.Problem.HttpResults;
using Humanizer;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
Expand Down Expand Up @@ -97,8 +95,8 @@ async Task<IResult> Handle([AsParameters] HttpCommand<TRequest> requestParameter
public static RouteHandlerBuilder MapQueryEndpoint<TRequestParameters, TResponse, TQuery, TQueryResult>(
this IEndpointRouteBuilder builder,
string pattern,
Func<TRequestParameters, TQuery>? mapRequestToQuery = null,
Func<TQueryResult, TResponse>? mapQueryResultToResponse = null
Func<TRequestParameters, TQuery> mapRequestToQuery,
Func<TQueryResult, TResponse> mapQueryResultToResponse
)
where TRequestParameters : IHttpQuery
where TResponse : class
Expand All @@ -115,18 +113,13 @@ public static RouteHandlerBuilder MapQueryEndpoint<TRequestParameters, TResponse
async Task<Ok<TResponse>> Handle([AsParameters] TRequestParameters requestParameters)
{
var queryProcessor = requestParameters.QueryBus;
var mapper = requestParameters.Mapper;
var cancellationToken = requestParameters.CancellationToken;

var query = mapRequestToQuery is not null
? mapRequestToQuery(requestParameters)
: mapper.Map<TQuery>(requestParameters);
var query = mapRequestToQuery(requestParameters);

var res = await queryProcessor.SendAsync(query, cancellationToken);

var response = mapQueryResultToResponse is not null
? mapQueryResultToResponse(res)
: mapper.Map<TResponse>(res);
var response = mapQueryResultToResponse(res);

// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/responses
// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/openapi?view=aspnetcore-7.0#multiple-response-types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ public async Task<GetProductsResult> Handle(GetProducts request, CancellationTok
.AsNoTracking()
.ApplyPagingAsync<Product, ProductReadModel>(
request,
mapper.ConfigurationProvider,
sieveProcessor,
mapper.ConfigurationProvider,
cancellationToken: cancellationToken
);

Expand Down

This file was deleted.

Loading

0 comments on commit f216b18

Please sign in to comment.