dynamic query support.

This commit is contained in:
David Lebee 2021-02-02 19:01:29 -05:00
parent 8175dc5f3d
commit ca307194db
26 changed files with 698 additions and 12 deletions

View File

@ -0,0 +1,54 @@
using PoweredSoft.Data.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.AsyncProvider
{
public class InMemoryQueryableHandler : IAsyncQueryableHandlerService
{
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.Any(predicate));
}
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.Any());
}
public bool CanHandle<T>(IQueryable<T> queryable)
{
var result = queryable is EnumerableQuery<T>;
return result;
}
public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.Count());
}
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.FirstOrDefault());
}
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.FirstOrDefault(predicate));
}
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.LongCount());
}
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(queryable.ToList());
}
}
}

View File

@ -6,6 +6,7 @@
<ItemGroup>
<PackageReference Include="FluentValidation.AspNetCore" Version="9.5.0" />
<PackageReference Include="PoweredSoft.Data" Version="2.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.6.3" />
@ -13,6 +14,9 @@
<ItemGroup>
<ProjectReference Include="..\PoweredSoft.CQRS.AspNetCore\PoweredSoft.CQRS.AspNetCore.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery.Abstractions\PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery.AspNetCore\PoweredSoft.CQRS.DynamicQuery.AspNetCore.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery\PoweredSoft.CQRS.DynamicQuery.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS\PoweredSoft.CQRS.csproj" />
</ItemGroup>

View File

@ -0,0 +1,29 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Demo.DynamicQueries
{
public class Contact
{
public long Id { get; set; }
public string DisplayName { get; set; }
}
public class ContactQueryableProvider : IQueryableProvider<Contact>
{
public Task<IQueryable<Contact>> GetQueryableAsync(object query, CancellationToken cancelllationToken = default)
{
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

@ -1,4 +1,6 @@
using Demo.AsyncProvider;
using Demo.Commands;
using Demo.DynamicQueries;
using Demo.Queries;
using FluentValidation;
using FluentValidation.AspNetCore;
@ -13,6 +15,12 @@ using Microsoft.Extensions.Logging;
using PoweredSoft.CQRS;
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.AspNetCore.Mvc;
using PoweredSoft.CQRS.DynamicQuery;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.CQRS.DynamicQuery.AspNetCore;
using PoweredSoft.Data;
using PoweredSoft.Data.Core;
using PoweredSoft.DynamicQuery;
using System;
using System.Collections.Generic;
using System.Linq;
@ -33,18 +41,30 @@ namespace Demo
public void ConfigureServices(IServiceCollection services)
{
AddQueries(services);
AddDynamicQueries(services);
AddCommands(services);
services.AddTransient<IAsyncQueryableHandlerService, InMemoryQueryableHandler>();
services.AddPoweredSoftDataServices();
services.AddPoweredSoftDynamicQuery();
services.AddPoweredSoftCQRS();
services
.AddControllers()
.AddPoweredSoftQueries()
.AddPoweredSoftCommands()
.AddPoweredSoftDynamicQueries()
.AddFluentValidation();
services.AddSwaggerGen();
}
private void AddDynamicQueries(IServiceCollection services)
{
services.AddTransient<IQueryableProvider<Contact>, ContactQueryableProvider>();
services.AddDynamicQuery<Contact, Contact>();
}
private void AddCommands(IServiceCollection services)
{
services.AddCommand<CreatePersonCommand, CreatePersonCommandHandler>();

View File

@ -11,5 +11,6 @@ namespace PoweredSoft.CQRS.Abstractions.Discovery
Type QueryType { get; }
Type ServiceType { get; }
Type QueryResultType { get; }
string Category { get; }
}
}

View File

@ -27,5 +27,6 @@ namespace PoweredSoft.CQRS.Abstractions.Discovery
public virtual Type QueryType { get; }
public virtual Type ServiceType { get; }
public virtual Type QueryResultType { get; }
public virtual string Category => "BasicQuery";
}
}

View File

@ -5,23 +5,23 @@ using System;
namespace PoweredSoft.CQRS.AspNetCore.Mvc
{
public class QueryControllerConvention : IControllerModelConvention
public class CommandControllerConvention : IControllerModelConvention
{
private readonly IServiceProvider serviceProvider;
public QueryControllerConvention(IServiceProvider serviceProvider)
public CommandControllerConvention(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public void Apply(ControllerModel controller)
{
if (controller.ControllerType.IsGenericType && controller.ControllerType.Name.Contains("QueryController") && controller.ControllerType.Assembly == typeof(QueryControllerConvention).Assembly)
if (controller.ControllerType.IsGenericType && controller.ControllerType.Name.Contains("CommandController") && controller.ControllerType.Assembly == typeof(CommandControllerConvention).Assembly)
{
var genericType = controller.ControllerType.GenericTypeArguments[0];
var queryDiscovery = this.serviceProvider.GetRequiredService<IQueryDiscovery>();
var query = queryDiscovery.FindQuery(genericType);
controller.ControllerName = query.Name;
var commandDiscovery = this.serviceProvider.GetRequiredService<ICommandDiscovery>();
var command = commandDiscovery.FindCommand(genericType);
controller.ControllerName = command.Name;
}
}
}

View File

@ -5,23 +5,23 @@ using System;
namespace PoweredSoft.CQRS.AspNetCore.Mvc
{
public class CommandControllerConvention : IControllerModelConvention
public class QueryControllerConvention : IControllerModelConvention
{
private readonly IServiceProvider serviceProvider;
public CommandControllerConvention(IServiceProvider serviceProvider)
public QueryControllerConvention(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public void Apply(ControllerModel controller)
{
if (controller.ControllerType.IsGenericType && controller.ControllerType.Name.Contains("CommandController") && controller.ControllerType.Assembly == typeof(CommandControllerConvention).Assembly)
if (controller.ControllerType.IsGenericType && controller.ControllerType.Name.Contains("QueryController") && controller.ControllerType.Assembly == typeof(QueryControllerConvention).Assembly)
{
var genericType = controller.ControllerType.GenericTypeArguments[0];
var commandDiscovery = this.serviceProvider.GetRequiredService<ICommandDiscovery>();
var command = commandDiscovery.FindCommand(genericType);
controller.ControllerName = command.Name;
var queryDiscovery = this.serviceProvider.GetRequiredService<IQueryDiscovery>();
var query = queryDiscovery.FindQuery(genericType);
controller.ControllerName = query.Name;
}
}
}

View File

@ -28,6 +28,9 @@ namespace PoweredSoft.CQRS.AspNetCore.Mvc
if (ignoreAttribute != null)
continue;
if (f.Category != "BasicQuery")
continue;
var controllerType = typeof(QueryController<,>).MakeGenericType(f.QueryType, f.QueryResultType);
var controllerTypeInfo = controllerType.GetTypeInfo();
feature.Controllers.Add(controllerTypeInfo);

View File

@ -0,0 +1,25 @@
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
{
public interface IDynamicQuery<TSource, TDestination> : IDynamicQuery
where TSource : class
where TDestination : class
{
}
public interface IDynamicQuery
{
List<IFilter> GetFilters();
List<IGroup> GetGroups();
List<ISort> GetSorts();
List<IAggregate> GetAggregates();
int? GetPage();
int? GetPageSize();
}
}

View File

@ -0,0 +1,8 @@
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
{
public interface IDynamicQueryParams<TParams>
where TParams : class
{
TParams GetParams();
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.DynamicQuery.Abstractions
{
public interface IQueryableProvider<TSource>
{
Task<IQueryable<TSource>> GetQueryableAsync(object query, CancellationToken cancelllationToken = default);
}
}

View File

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="PoweredSoft.DynamicQuery.Core" Version="2.1.4" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,71 @@
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
{
public class DynamicQuery<TSource, TDestination> : DynamicQuery, IDynamicQuery<TSource, TDestination>
where TSource : class
where TDestination : class
{
}
public class DynamicQuery<TSource, TDestination, TParams> : DynamicQuery, IDynamicQuery<TSource, TDestination>, IDynamicQueryParams<TParams>
where TSource : class
where TDestination : class
where TParams : class
{
public TParams Params { get; set; }
public TParams GetParams()
{
return Params;
}
}
public class DynamicQuery : IDynamicQuery
{
public int? Page { get; set; }
public int? PageSize { get; set; }
public List<Sort> Sorts { get; set; }
public List<Aggregate> Aggregates { get; set; }
public List<Group> Groups { get; set; }
public List<DynamicQueryFilter> Filters { get; set; }
public List<IAggregate> GetAggregates()
{
return Aggregates?.AsEnumerable<IAggregate>()?.ToList();
}
public List<IFilter> GetFilters()
{
return Filters?.Select(t => t.ToFilter())?.ToList();
}
public List<IGroup> GetGroups()
{
return this.Groups?.AsEnumerable<IGroup>()?.ToList();
}
public int? GetPage()
{
return this.Page;
}
public int? GetPageSize()
{
return this.PageSize;
}
public List<ISort> GetSorts()
{
return this.Sorts?.AsEnumerable<ISort>()?.ToList();
}
}
}

View File

@ -0,0 +1,59 @@
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
{
public class DynamicQueryFilter
{
public List<DynamicQueryFilter> Filters { get; set; }
public bool? And { get; set; }
public FilterType Type { get; set; }
public bool? Not { get; set; }
public string Path { get; set; }
public object Value { get; set; }
public IFilter ToFilter()
{
if (Type == FilterType.Composite)
{
var compositeFilter = new CompositeFilter
{
And = And,
Type = FilterType.Composite,
Filters = Filters?.Select(t => t.ToFilter())?.ToList() ?? new List<IFilter>()
};
return compositeFilter;
}
object value = Value;
if (Value is JsonElement jsonElement)
{
if (jsonElement.ValueKind == JsonValueKind.String)
value = jsonElement.ToString();
else if (jsonElement.ValueKind == JsonValueKind.Number && jsonElement.TryGetInt64(out var l))
value = l;
else if (jsonElement.ValueKind == JsonValueKind.True)
value = true;
else if (jsonElement.ValueKind == JsonValueKind.False)
value = false;
else if (jsonElement.ValueKind == JsonValueKind.Array)
throw new System.Exception("TODO");
else
value = null;
}
var simpleFilter = new SimpleFilter
{
And = And,
Type = Type,
Not = Not,
Path = Path,
Value = value
};
return simpleFilter;
}
}
}

View File

@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Mvc;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
{
[ApiController, Route("api/query/[controller]")]
public class DynamicQueryController<TUnderlyingQuery, TSource, TDestination> : Controller
where TSource : class
where TDestination : class
{
[HttpPost]
public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
[FromBody] DynamicQuery<TSource, TDestination> query,
[FromServices]PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
)
{
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
return result;
}
}
[ApiController, Route("api/query/[controller]")]
public class DynamicQueryController<TUnderlyingQuery, TSource, TDestination, TParams> : Controller
where TSource : class
where TDestination : class
where TParams : class
{
[HttpPost]
public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
[FromBody] DynamicQuery<TSource, TDestination, TParams> query,
[FromServices] PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
)
{
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
return result;
}
}
}

View File

@ -0,0 +1,30 @@
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.Abstractions.Discovery;
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
{
public class DynamicQueryControllerConvention : IControllerModelConvention
{
private readonly IServiceProvider serviceProvider;
public DynamicQueryControllerConvention(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public void Apply(ControllerModel controller)
{
if (controller.ControllerType.IsGenericType && controller.ControllerType.Name.Contains("DynamicQueryController") && controller.ControllerType.Assembly == typeof(DynamicQueryControllerConvention).Assembly)
{
var genericType = controller.ControllerType.GenericTypeArguments[0];
var queryDiscovery = this.serviceProvider.GetRequiredService<IQueryDiscovery>();
var query = queryDiscovery.FindQuery(genericType);
controller.ControllerName = query.Name;
}
}
}
}

View File

@ -0,0 +1,53 @@
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.Abstractions.Discovery;
using PoweredSoft.CQRS.AspNetCore.Abstractions.Attributes;
using PoweredSoft.CQRS.DynamicQuery.Discover;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
{
public class DynamicQueryControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
{
private readonly ServiceProvider serviceProvider;
public DynamicQueryControllerFeatureProvider(ServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
{
var queryDiscovery = this.serviceProvider.GetRequiredService<IQueryDiscovery>();
foreach (var f in queryDiscovery.GetQueries())
{
var ignoreAttribute = f.QueryType.GetCustomAttribute<QueryControllerIgnoreAttribute>();
if (ignoreAttribute != null)
continue;
if (f.Category != "DynamicQuery")
continue;
if (f is DynamicQueryMeta dynamicQueryMeta)
{
if (dynamicQueryMeta.ParamsType == null)
{
var controllerType = typeof(DynamicQueryController<,,>).MakeGenericType(f.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType);
var controllerTypeInfo = controllerType.GetTypeInfo();
feature.Controllers.Add(controllerTypeInfo);
}
else
{
var controllerType = typeof(DynamicQueryController<,,,>).MakeGenericType(f.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType, dynamicQueryMeta.ParamsType);
var controllerTypeInfo = controllerType.GetTypeInfo();
feature.Controllers.Add(controllerTypeInfo);
}
}
}
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc
{
public class DynamicQueryControllerOptions
{
}
}

View File

@ -0,0 +1,25 @@
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.CQRS.DynamicQuery.AspNetCore.Mvc;
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace PoweredSoft.CQRS.DynamicQuery.AspNetCore
{
public static class MvcBuilderExtensions
{
public static IMvcBuilder AddPoweredSoftDynamicQueries(this IMvcBuilder builder, Action<DynamicQueryControllerOptions> configuration = null)
{
var options = new DynamicQueryControllerOptions();
configuration?.Invoke(options);
var services = builder.Services;
var serviceProvider = services.BuildServiceProvider();
builder.AddMvcOptions(o => o.Conventions.Add(new DynamicQueryControllerConvention(serviceProvider)));
builder.ConfigureApplicationPartManager(m => m.FeatureProviders.Add(new DynamicQueryControllerFeatureProvider(serviceProvider)));
return builder;
}
}
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PoweredSoft.CQRS.Abstractions\PoweredSoft.CQRS.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.AspNetCore.Abstractions\PoweredSoft.CQRS.AspNetCore.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery.Abstractions\PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery\PoweredSoft.CQRS.DynamicQuery.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,33 @@
using PoweredSoft.CQRS.Abstractions.Discovery;
using PoweredSoft.CQRS.Discovery;
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery.Discover
{
public class DynamicQueryMeta : QueryMeta
{
public DynamicQueryMeta(Type queryType, Type serviceType, Type queryResultType) : base(queryType, serviceType, queryResultType)
{
}
public Type SourceType => QueryType.GetGenericArguments()[0];
public Type DestinationType => QueryType.GetGenericArguments()[1];
public override string Category => "DynamicQuery";
public override string Name
{
get
{
if (NameAttribute != null)
return NameAttribute.Name;
var pluralizer = new Pluralize.NET.Pluralizer();
return pluralizer.Pluralize(DestinationType.Name);
}
}
public Type ParamsType { get; internal set; }
}
}

View File

@ -0,0 +1,85 @@
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 class DynamicQueryHandler<TSource, TDestination> :
PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>>
where TSource : class
where TDestination : class
{
private readonly IQueryHandlerAsync queryHandlerAsync;
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)
{
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;
}
public async Task<IQueryExecutionResult<TDestination>> HandleAsync(IDynamicQuery<TSource, TDestination> query, CancellationToken cancellationToken = default)
{
return await ProcessQueryAsync(query, cancellationToken);
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Pluralize.NET" Version="1.0.2" />
<PackageReference Include="PoweredSoft.DynamicQuery" Version="2.1.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PoweredSoft.CQRS.DynamicQuery.Abstractions\PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj" />
<ProjectReference Include="..\PoweredSoft.CQRS\PoweredSoft.CQRS.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,54 @@
using Microsoft.Extensions.DependencyInjection;
using PoweredSoft.CQRS.Abstractions;
using PoweredSoft.CQRS.Abstractions.Discovery;
using PoweredSoft.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.CQRS.DynamicQuery.Discover;
using PoweredSoft.DynamicQuery.Core;
using System;
using System.Collections.Generic;
using System.Text;
namespace PoweredSoft.CQRS.DynamicQuery
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddDynamicQuery<TSource, TDestination>(this IServiceCollection services)
where TSource : class
where TDestination : class
{
// add query handler.
services.AddTransient<PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination>>();
// add for discovery purposes.
var queryType = typeof(IDynamicQuery<TSource, TDestination>);
var resultType = typeof(IQueryExecutionResult<TDestination>);
var serviceType = typeof(DynamicQueryHandler<TSource, TDestination>);
var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType);
services.AddSingleton<IQueryMeta>(queryMeta);
return services;
}
public static IServiceCollection AddDynamicQueryWithParams<TSource, TDestination, TParams>(this IServiceCollection services)
where TSource : class
where TDestination : class
{
// add query handler.
services.AddTransient<PoweredSoft.CQRS.Abstractions.IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>>, DynamicQueryHandler<TSource, TDestination>>();
// add for discovery purposes.
var queryType = typeof(IDynamicQuery<TSource, TDestination>);
var resultType = typeof(IQueryExecutionResult<TDestination>);
var serviceType = typeof(DynamicQueryHandler<TSource, TDestination>);
var queryMeta = new DynamicQueryMeta(queryType, serviceType, resultType);
// params type.
queryMeta.ParamsType = typeof(TParams);
services.AddSingleton<IQueryMeta>(queryMeta);
return services;
}
}
}

View File

@ -19,6 +19,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PoweredSoft.CQRS.DynamicQuery", "PoweredSoft.CQRS.DynamicQuery\PoweredSoft.CQRS.DynamicQuery.csproj", "{A38CE930-191F-417C-B5BE-8CC62DB47513}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PoweredSoft.CQRS.DynamicQuery.Abstractions", "PoweredSoft.CQRS.DynamicQuery.Abstractions\PoweredSoft.CQRS.DynamicQuery.Abstractions.csproj", "{60B5E255-77B8-48E0-AE8F-04E8332970F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PoweredSoft.CQRS.DynamicQuery.AspNetCore", "PoweredSoft.CQRS.DynamicQuery.AspNetCore\PoweredSoft.CQRS.DynamicQuery.AspNetCore.csproj", "{0829B99A-0A20-4CAC-A91E-FB67E18444DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -45,6 +51,18 @@ Global
{F15B1E11-8D4C-489E-AFF7-AA144105FE46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F15B1E11-8D4C-489E-AFF7-AA144105FE46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F15B1E11-8D4C-489E-AFF7-AA144105FE46}.Release|Any CPU.Build.0 = Release|Any CPU
{A38CE930-191F-417C-B5BE-8CC62DB47513}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A38CE930-191F-417C-B5BE-8CC62DB47513}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A38CE930-191F-417C-B5BE-8CC62DB47513}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A38CE930-191F-417C-B5BE-8CC62DB47513}.Release|Any CPU.Build.0 = Release|Any CPU
{60B5E255-77B8-48E0-AE8F-04E8332970F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60B5E255-77B8-48E0-AE8F-04E8332970F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60B5E255-77B8-48E0-AE8F-04E8332970F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60B5E255-77B8-48E0-AE8F-04E8332970F9}.Release|Any CPU.Build.0 = Release|Any CPU
{0829B99A-0A20-4CAC-A91E-FB67E18444DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0829B99A-0A20-4CAC-A91E-FB67E18444DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0829B99A-0A20-4CAC-A91E-FB67E18444DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0829B99A-0A20-4CAC-A91E-FB67E18444DE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE