more adjusted to support params.

This commit is contained in:
David Lebee 2021-02-02 19:32:39 -05:00
parent ca307194db
commit 30e15e310c
10 changed files with 151 additions and 91 deletions

View File

@ -1,9 +1,4 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions; using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.DynamicQueries namespace Demo.DynamicQueries
{ {
@ -13,17 +8,8 @@ namespace Demo.DynamicQueries
public string DisplayName { get; set; } public string DisplayName { get; set; }
} }
public class ContactQueryableProvider : IQueryableProvider<Contact> public class SearchContactParams
{ {
public Task<IQueryable<Contact>> GetQueryableAsync(object query, CancellationToken cancelllationToken = default) public string SearchDisplayName { get; set; }
{
var ret = new List<Contact>
{
new Contact { Id = 1, DisplayName = "David L"},
new Contact { Id = 2, DisplayName = "John Doe"}
};
return Task.FromResult(ret.AsQueryable());
}
} }
} }

View File

@ -0,0 +1,23 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.DynamicQueries
{
public class ContactQueryableProvider : IQueryableProvider<Contact>
{
public Task<IQueryable<Contact>> GetQueryableAsync(object query, CancellationToken cancelllationToken = default)
{
var source = new List<Contact>
{
new Contact { Id = 1, DisplayName = "David L"},
new Contact { Id = 2, DisplayName = "John Doe"}
};
var ret = source.AsQueryable();
return Task.FromResult(ret);
}
}
}

View File

@ -63,6 +63,7 @@ namespace Demo
{ {
services.AddTransient<IQueryableProvider<Contact>, ContactQueryableProvider>(); services.AddTransient<IQueryableProvider<Contact>, ContactQueryableProvider>();
services.AddDynamicQuery<Contact, Contact>(); services.AddDynamicQuery<Contact, Contact>();
services.AddDynamicQueryWithParams<Contact, Contact, SearchContactParams>(name: "SearchContacts");
} }
private void AddCommands(IServiceCollection services) private void AddCommands(IServiceCollection services)

View File

@ -12,6 +12,14 @@ namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
} }
public interface IDynamicQuery<TSource, TDestination, TParams> : IDynamicQuery<TSource, TDestination>, IDynamicQueryParams<TParams>
where TSource : class
where TDestination : class
where TParams : class
{
}
public interface IDynamicQuery public interface IDynamicQuery
{ {

View File

@ -15,7 +15,7 @@ namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
} }
public class DynamicQuery<TSource, TDestination, TParams> : DynamicQuery, IDynamicQuery<TSource, TDestination>, IDynamicQueryParams<TParams> public class DynamicQuery<TSource, TDestination, TParams> : DynamicQuery, IDynamicQuery<TSource, TDestination, TParams>
where TSource : class where TSource : class
where TDestination : class where TDestination : class
where TParams : class where TParams : class

View File

@ -33,7 +33,7 @@ namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
[HttpPost] [HttpPost]
public async Task<IQueryExecutionResult<TDestination>> HandleAsync( public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
[FromBody] DynamicQuery<TSource, TDestination, TParams> query, [FromBody] DynamicQuery<TSource, TDestination, TParams> query,
[FromServices] PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler [FromServices] PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
) )
{ {
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted); var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);

View File

@ -20,8 +20,8 @@ namespace PoweredSoft.CQRS.DynamicQuery.Discover
{ {
get get
{ {
if (NameAttribute != null) if (OverridableName != null)
return NameAttribute.Name; return OverridableName;
var pluralizer = new Pluralize.NET.Pluralizer(); var pluralizer = new Pluralize.NET.Pluralizer();
return pluralizer.Pluralize(DestinationType.Name); return pluralizer.Pluralize(DestinationType.Name);
@ -29,5 +29,6 @@ namespace PoweredSoft.CQRS.DynamicQuery.Discover
} }
public Type ParamsType { get; internal set; } public Type ParamsType { get; internal set; }
public string OverridableName { get; internal set; }
} }
} }

View File

@ -1,85 +1,41 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions; using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core; using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PoweredSoft.CQRS.DynamicQuery namespace PoweredSoft.CQRS.DynamicQuery
{ {
public class DynamicQueryHandler<TSource, TDestination> : public class DynamicQueryHandler<TSource, TDestination>
: DynamicQueryHandlerBase<TSource, TDestination>,
PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>>
where TSource : class where TSource : class
where TDestination : class where TDestination : class
{ {
private readonly IQueryHandlerAsync queryHandlerAsync; public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync, IEnumerable<IQueryableProvider<TSource>> queryableProviders) : base(queryHandlerAsync, queryableProviders)
private readonly IEnumerable<IQueryableProvider<TSource>> queryableProviders;
public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync,
IEnumerable<IQueryableProvider<TSource>> queryableProviders)
{ {
this.queryHandlerAsync = queryHandlerAsync;
this.queryableProviders = queryableProviders;
} }
protected virtual Task<IQueryable<TSource>> GetQueryableAsync(IDynamicQuery query, CancellationToken cancellationToken = default) public Task<IQueryExecutionResult<TDestination>> HandleAsync(IDynamicQuery<TSource, TDestination> query, CancellationToken cancellationToken = default)
{ {
if (this.queryableProviders.Any()) return ProcessQueryAsync(query, cancellationToken);
return queryableProviders.ElementAt(0).GetQueryableAsync(query, cancellationToken); }
}
throw new Exception($"You must provide a QueryableProvider<TSource> for {typeof(TSource).Name}"); public class DynamicQueryHandler<TSource, TDestination, TParams>
: DynamicQueryHandlerBase<TSource, TDestination>,
PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>>
where TSource : class
where TDestination : class
where TParams : class
{
public DynamicQueryHandler(IQueryHandlerAsync queryHandlerAsync, IEnumerable<IQueryableProvider<TSource>> queryableProviders) : base(queryHandlerAsync, queryableProviders)
{
} }
public virtual IQueryExecutionOptions GetQueryExecutionOptions(IQueryable<TSource> source, IDynamicQuery query) public Task<IQueryExecutionResult<TDestination>> HandleAsync(IDynamicQuery<TSource, TDestination, TParams> query, CancellationToken cancellationToken = default)
{ {
return new QueryExecutionOptions(); return this.ProcessQueryAsync(query, cancellationToken);
}
public virtual IEnumerable<IQueryInterceptor> GetInterceptors()
{
return Enumerable.Empty<IQueryInterceptor>();
}
protected async Task<IQueryExecutionResult<TDestination>> ProcessQueryAsync(IDynamicQuery query, CancellationToken cancellationToken = default)
{
var source = await GetQueryableAsync(query, cancellationToken);
source = await AlterSourceAsync(source, query, cancellationToken);
var options = GetQueryExecutionOptions(source, query);
var interceptors = this.GetInterceptors();
foreach (var interceptor in interceptors)
queryHandlerAsync.AddInterceptor(interceptor);
var criteria = CreateCriteriaFromQuery(query);
var result = await queryHandlerAsync.ExecuteAsync<TSource, TDestination>(source, criteria, options, cancellationToken);
return result;
}
protected virtual Task<IQueryable<TSource>> AlterSourceAsync(IQueryable<TSource> source, IDynamicQuery query, CancellationToken cancellationToken)
{
return Task.FromResult(source);
}
protected virtual IQueryCriteria CreateCriteriaFromQuery(IDynamicQuery query)
{
var criteria = new QueryCriteria
{
Page = query?.GetPage(),
PageSize = query?.GetPageSize(),
Filters = query?.GetFilters() ?? new List<IFilter>(),
Sorts = query?.GetSorts() ?? new List<ISort>(),
Groups = query.GetGroups() ?? new List<IGroup>(),
Aggregates = query.GetAggregates() ?? new List<IAggregate>()
};
return criteria;
}
public async Task<IQueryExecutionResult<TDestination>> HandleAsync(IDynamicQuery<TSource, TDestination> query, CancellationToken cancellationToken = default)
{
return await ProcessQueryAsync(query, cancellationToken);
} }
} }
} }

View File

@ -0,0 +1,78 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.DynamicQuery
{
public abstract class DynamicQueryHandlerBase<TSource, TDestination>
where TSource : class
where TDestination : class
{
private readonly IQueryHandlerAsync queryHandlerAsync;
private readonly IEnumerable<IQueryableProvider<TSource>> queryableProviders;
public DynamicQueryHandlerBase(IQueryHandlerAsync queryHandlerAsync,
IEnumerable<IQueryableProvider<TSource>> queryableProviders)
{
this.queryHandlerAsync = queryHandlerAsync;
this.queryableProviders = queryableProviders;
}
protected virtual Task<IQueryable<TSource>> GetQueryableAsync(IDynamicQuery query, CancellationToken cancellationToken = default)
{
if (this.queryableProviders.Any())
return queryableProviders.ElementAt(0).GetQueryableAsync(query, cancellationToken);
throw new Exception($"You must provide a QueryableProvider<TSource> for {typeof(TSource).Name}");
}
public virtual IQueryExecutionOptions GetQueryExecutionOptions(IQueryable<TSource> source, IDynamicQuery query)
{
return new QueryExecutionOptions();
}
public virtual IEnumerable<IQueryInterceptor> GetInterceptors()
{
return Enumerable.Empty<IQueryInterceptor>();
}
protected async Task<IQueryExecutionResult<TDestination>> ProcessQueryAsync(IDynamicQuery query, CancellationToken cancellationToken = default)
{
var source = await GetQueryableAsync(query, cancellationToken);
source = await AlterSourceAsync(source, query, cancellationToken);
var options = GetQueryExecutionOptions(source, query);
var interceptors = this.GetInterceptors();
foreach (var interceptor in interceptors)
queryHandlerAsync.AddInterceptor(interceptor);
var criteria = CreateCriteriaFromQuery(query);
var result = await queryHandlerAsync.ExecuteAsync<TSource, TDestination>(source, criteria, options, cancellationToken);
return result;
}
protected virtual Task<IQueryable<TSource>> AlterSourceAsync(IQueryable<TSource> source, IDynamicQuery query, CancellationToken cancellationToken)
{
return Task.FromResult(source);
}
protected virtual IQueryCriteria CreateCriteriaFromQuery(IDynamicQuery query)
{
var criteria = new QueryCriteria
{
Page = query?.GetPage(),
PageSize = query?.GetPageSize(),
Filters = query?.GetFilters() ?? new List<IFilter>(),
Sorts = query?.GetSorts() ?? new List<ISort>(),
Groups = query.GetGroups() ?? new List<IGroup>(),
Aggregates = query.GetAggregates() ?? new List<IAggregate>()
};
return criteria;
}
}
}

View File

@ -12,7 +12,7 @@ namespace PoweredSoft.CQRS.DynamicQuery
{ {
public static class ServiceCollectionExtensions public static class ServiceCollectionExtensions
{ {
public static IServiceCollection AddDynamicQuery<TSource, TDestination>(this IServiceCollection services) public static IServiceCollection AddDynamicQuery<TSource, TDestination>(this IServiceCollection services, string name = null)
where TSource : class where TSource : class
where TDestination : class where TDestination : class
{ {
@ -23,28 +23,35 @@ namespace PoweredSoft.CQRS.DynamicQuery
var queryType = typeof(IDynamicQuery<TSource, TDestination>); var queryType = typeof(IDynamicQuery<TSource, TDestination>);
var resultType = typeof(IQueryExecutionResult<TDestination>); var resultType = typeof(IQueryExecutionResult<TDestination>);
var serviceType = typeof(DynamicQueryHandler<TSource, TDestination>); var serviceType = typeof(DynamicQueryHandler<TSource, TDestination>);
var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType); var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType)
{
OverridableName = name
};
services.AddSingleton<IQueryMeta>(queryMeta); services.AddSingleton<IQueryMeta>(queryMeta);
return services; return services;
} }
public static IServiceCollection AddDynamicQueryWithParams<TSource, TDestination, TParams>(this IServiceCollection services) public static IServiceCollection AddDynamicQueryWithParams<TSource, TDestination, TParams>(this IServiceCollection services, string name = null)
where TSource : class where TSource : class
where TDestination : class where TDestination : class
where TParams : class
{ {
// add query handler. // add query handler.
services.AddTransient<PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination>>(); services.AddTransient<PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination, TParams>>();
// add for discovery purposes. // add for discovery purposes.
var queryType = typeof(IDynamicQuery<TSource, TDestination>); var queryType = typeof(IDynamicQuery<TSource, TDestination, TParams>);
var resultType = typeof(IQueryExecutionResult<TDestination>); var resultType = typeof(IQueryExecutionResult<TDestination>);
var serviceType = typeof(DynamicQueryHandler<TSource, TDestination>); var serviceType = typeof(DynamicQueryHandler<TSource, TDestination>);
var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType); var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType)
{
// params type. // params type.
queryMeta.ParamsType = typeof(TParams); ParamsType = typeof(TParams),
OverridableName = name
};
services.AddSingleton<IQueryMeta>(queryMeta); services.AddSingleton<IQueryMeta>(queryMeta);