diff --git a/src/Fluxera.Repository.Queries/Fluxera.Repository.Queries.csproj b/src/Fluxera.Repository.Queries/Fluxera.Repository.Queries.csproj index d6a0ce0..26eda95 100644 --- a/src/Fluxera.Repository.Queries/Fluxera.Repository.Queries.csproj +++ b/src/Fluxera.Repository.Queries/Fluxera.Repository.Queries.csproj @@ -22,6 +22,8 @@ + + all diff --git a/src/Fluxera.Repository.Queries/RepositoryExtensions.cs b/src/Fluxera.Repository.Queries/RepositoryExtensions.cs index ceada79..9e52dfb 100644 --- a/src/Fluxera.Repository.Queries/RepositoryExtensions.cs +++ b/src/Fluxera.Repository.Queries/RepositoryExtensions.cs @@ -5,9 +5,12 @@ using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; + using AutoMapper; + using AutoMapper.Extensions.ExpressionMapping; using Fluxera.Entity; using Fluxera.Guards; using Fluxera.Queries; + using Fluxera.Queries.Expressions; using Fluxera.Queries.Options; using Fluxera.Repository; using Fluxera.Repository.Query; @@ -19,6 +22,138 @@ [PublicAPI] public static class RepositoryExtensions { + /// + /// Executes the find many query defined by the given . + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task ExecuteFindManyAsync(this IReadOnlyRepository repository, + QueryOptions queryOptions, + IMapper mapper, + IQueryOptionsBuilder queryOptionsBuilder, + CancellationToken cancellationToken = default) + where TAggregateRoot : AggregateRoot + where TKey : IComparable, IEquatable + where TDto : class + { + Guard.Against.Null(queryOptions); + + // 1. Build the query options: sorting and paging. + IReadOnlyCollection> orderBy = queryOptions.ToOrderBy(); + IList> mappedOrderBy = new List>(); + + foreach(OrderByExpression orderByExpression in orderBy) + { + Expression> mappedSelectorExpression = mapper.Map>>(orderByExpression.SelectorExpression); + OrderByExpression mappedOrderByExpression = new OrderByExpression(mappedSelectorExpression, orderByExpression.Direction); + mappedOrderBy.Add(mappedOrderByExpression); + } + + IQueryOptions mappedOptions = queryOptionsBuilder + .Apply(mappedOrderBy.AsReadOnly()) + .Apply(queryOptions.Skip, queryOptions.Top) + .Build(); + + // 2. Build the query predicate. + Expression> predicate = queryOptions.ToPredicate(); + Expression> mappedPredicate = mapper.MapExpression>>(predicate); + + // 3. Build the selector expression (optional). + Expression> selector = queryOptions.ToSelector(); + Expression> mappedSelector = mapper.MapExpression>>(selector); + + // 4. Get the total count of the query (optional). + long? totalCount = null; + if(queryOptions.Count is not null) + { + if(queryOptions.Count.CountValue) + { + totalCount = await repository.CountAsync(mappedPredicate, cancellationToken); + } + } + + // 5. Execute the find many query. + IReadOnlyCollection items = selector is null + ? await repository.FindManyAsync(mappedPredicate, mappedOptions, cancellationToken) + : await repository.FindManyAsync(mappedPredicate, mappedSelector, mappedOptions, cancellationToken); + + return new QueryResult(items, totalCount); + } + + /// + /// Executes the get query defined by the given ID and . + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task ExecuteGetAsync(this IReadOnlyRepository repository, + TKey id, + QueryOptions queryOptions, + IMapper mapper, + CancellationToken cancellationToken = default) + where TAggregateRoot : AggregateRoot + where TKey : IComparable, IEquatable + where TDto : class + { + Guard.Against.Null(id); + Guard.Against.Null(queryOptions); + + // 1. Build the selector expression (optional). + Expression> selector = queryOptions.ToSelector(); + Expression> mappedSelector = mapper.MapExpression>>(selector); + + // 2. Execute the get query. + TAggregateRoot item = selector is null + ? await repository.GetAsync(id, cancellationToken) + : await repository.GetAsync(id, mappedSelector, cancellationToken); + + return new SingleResult(item); + } + + /// + /// Executes the count query defined by the given . + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task ExecuteCountAsync(this IReadOnlyRepository repository, + QueryOptions queryOptions, + IMapper mapper, + CancellationToken cancellationToken = default) + where TAggregateRoot : AggregateRoot + where TKey : IComparable, IEquatable + where TDto : class + { + Guard.Against.Null(queryOptions); + + // 1. Build the query predicate. + Expression> predicate = queryOptions.ToPredicate(); + Expression> mappedPredicate = mapper.MapExpression>>(predicate); + + // 2. Execute the count query. + long count = await repository.CountAsync(mappedPredicate, cancellationToken); + + return count; + } + /// /// Executes the get query defined by the given and . ///