cat on a spaceship
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Svrnty.CQRS.DynamicQuery.Abstractions;
|
||||
using PoweredSoft.DynamicQuery;
|
||||
using PoweredSoft.DynamicQuery.Core;
|
||||
|
||||
namespace Svrnty.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, 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<DynamicQueryAggregate> Aggregates { get; set; }
|
||||
public List<Group> Groups { get; set; }
|
||||
public List<DynamicQueryFilter> Filters { get; set; }
|
||||
|
||||
|
||||
public List<IAggregate> GetAggregates()
|
||||
{
|
||||
return Aggregates?.Select(t => t.ToAggregate())?.ToList();//.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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using PoweredSoft.DynamicQuery;
|
||||
using PoweredSoft.DynamicQuery.Core;
|
||||
using System;
|
||||
|
||||
namespace Svrnty.CQRS.DynamicQuery.AspNetCore;
|
||||
|
||||
public class DynamicQueryAggregate
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string Type { get; set; }
|
||||
|
||||
public IAggregate ToAggregate()
|
||||
{
|
||||
return new Aggregate
|
||||
{
|
||||
Type = Enum.Parse<AggregateType>(Type),
|
||||
Path = Path
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PoweredSoft.DynamicQuery;
|
||||
using PoweredSoft.DynamicQuery.Core;
|
||||
|
||||
namespace Svrnty.CQRS.DynamicQuery.AspNetCore;
|
||||
|
||||
public class DynamicQueryFilter
|
||||
{
|
||||
public List<DynamicQueryFilter> Filters { get; set; }
|
||||
public bool? And { get; set; }
|
||||
public string Type { get; set; }
|
||||
public bool? Not { get; set; }
|
||||
public string Path { get; set; }
|
||||
public object Value { get; set; }
|
||||
|
||||
[FromQuery(Name ="value")]
|
||||
public string QueryValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool? CaseInsensitive { get; set; }
|
||||
|
||||
public IFilter ToFilter()
|
||||
{
|
||||
var type = Enum.Parse<FilterType>(Type);
|
||||
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)
|
||||
{
|
||||
switch (jsonElement.ValueKind)
|
||||
{
|
||||
case JsonValueKind.String:
|
||||
value = jsonElement.ToString();
|
||||
break;
|
||||
case JsonValueKind.Number:
|
||||
if (jsonElement.ToString().Contains('.'))
|
||||
value = jsonElement.GetDecimal();
|
||||
else if (jsonElement.TryGetInt64(out var convertedValue))
|
||||
value = convertedValue;
|
||||
break;
|
||||
case JsonValueKind.True:
|
||||
value = true;
|
||||
break;
|
||||
case JsonValueKind.False:
|
||||
value = false;
|
||||
break;
|
||||
// TODO: Array support
|
||||
default:
|
||||
value = null;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var simpleFilter = new SimpleFilter
|
||||
{
|
||||
And = And,
|
||||
Type = type,
|
||||
Not = Not,
|
||||
Path = Path,
|
||||
Value = value,
|
||||
CaseInsensitive = CaseInsensitive,
|
||||
};
|
||||
return simpleFilter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Svrnty.CQRS.Abstractions;
|
||||
using Svrnty.CQRS.AspNetCore.Abstractions.Attributes;
|
||||
using Svrnty.CQRS.DynamicQuery.Abstractions;
|
||||
using PoweredSoft.DynamicQuery.Core;
|
||||
|
||||
namespace Svrnty.CQRS.DynamicQuery.AspNetCore.Mvc;
|
||||
|
||||
[ApiController, Route("api/query/[controller]")]
|
||||
public class DynamicQueryController<TUnderlyingQuery, TSource, TDestination> : Controller
|
||||
where TSource : class
|
||||
where TDestination : class
|
||||
{
|
||||
[HttpPost, QueryControllerAuthorization]
|
||||
public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
|
||||
[FromBody] DynamicQuery<TSource, TDestination> query,
|
||||
[FromServices]IQueryHandler<IDynamicQuery<TSource, TDestination>, IQueryExecutionResult<TDestination>> queryHandler
|
||||
)
|
||||
{
|
||||
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpGet, QueryControllerAuthorization]
|
||||
public async Task<IQueryExecutionResult<TDestination>> HandleGetAsync(
|
||||
[FromQuery] DynamicQuery<TSource, TDestination> query,
|
||||
[FromServices] 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, QueryControllerAuthorization]
|
||||
public async Task<IQueryExecutionResult<TDestination>> HandleAsync(
|
||||
[FromBody] DynamicQuery<TSource, TDestination, TParams> query,
|
||||
[FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
|
||||
)
|
||||
{
|
||||
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpGet, QueryControllerAuthorization]
|
||||
public async Task<IQueryExecutionResult<TDestination>> HandleGetAsync(
|
||||
[FromQuery] DynamicQuery<TSource, TDestination, TParams> query,
|
||||
[FromServices] IQueryHandler<IDynamicQuery<TSource, TDestination, TParams>, IQueryExecutionResult<TDestination>> queryHandler
|
||||
)
|
||||
{
|
||||
var result = await queryHandler.HandleAsync(query, HttpContext.RequestAborted);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Svrnty.CQRS.Abstractions.Discovery;
|
||||
|
||||
namespace Svrnty.CQRS.DynamicQuery.AspNetCore.Mvc;
|
||||
|
||||
public class DynamicQueryControllerConvention : IControllerModelConvention
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public DynamicQueryControllerConvention(IServiceProvider serviceProvider)
|
||||
{
|
||||
_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 = _serviceProvider.GetRequiredService<IQueryDiscovery>();
|
||||
var query = queryDiscovery.FindQuery(genericType);
|
||||
controller.ControllerName = query.LowerCamelCaseName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Svrnty.CQRS.Abstractions.Discovery;
|
||||
using Svrnty.CQRS.AspNetCore.Abstractions.Attributes;
|
||||
using Svrnty.CQRS.DynamicQuery.Discover;
|
||||
|
||||
namespace Svrnty.CQRS.DynamicQuery.AspNetCore.Mvc;
|
||||
|
||||
public class DynamicQueryControllerFeatureProvider(ServiceProvider serviceProvider)
|
||||
: IApplicationFeatureProvider<ControllerFeature>
|
||||
{
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
|
||||
{
|
||||
var queryDiscovery = serviceProvider.GetRequiredService<IQueryDiscovery>();
|
||||
foreach (var queryMeta in queryDiscovery.GetQueries())
|
||||
{
|
||||
var ignoreAttribute = queryMeta.QueryType.GetCustomAttribute<QueryControllerIgnoreAttribute>();
|
||||
if (ignoreAttribute != null)
|
||||
continue;
|
||||
|
||||
if (queryMeta.Category != "DynamicQuery")
|
||||
continue;
|
||||
|
||||
if (queryMeta is DynamicQueryMeta dynamicQueryMeta)
|
||||
{
|
||||
// todo: add better error output for the user
|
||||
|
||||
if (dynamicQueryMeta.ParamsType == null)
|
||||
{
|
||||
// todo: not aot friendly
|
||||
var controllerType = typeof(DynamicQueryController<,,>).MakeGenericType(queryMeta.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType);
|
||||
var controllerTypeInfo = controllerType.GetTypeInfo();
|
||||
feature.Controllers.Add(controllerTypeInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// todo: not aot friendly
|
||||
var controllerType = typeof(DynamicQueryController<,,,>).MakeGenericType(queryMeta.QueryType, dynamicQueryMeta.SourceType, dynamicQueryMeta.DestinationType, dynamicQueryMeta.ParamsType);
|
||||
var controllerTypeInfo = controllerType.GetTypeInfo();
|
||||
feature.Controllers.Add(controllerTypeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Svrnty.CQRS.DynamicQuery.AspNetCore.Mvc;
|
||||
|
||||
public class DynamicQueryControllerOptions
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Svrnty.CQRS.DynamicQuery.AspNetCore.Mvc;
|
||||
|
||||
namespace Svrnty.CQRS.DynamicQuery.AspNetCore;
|
||||
|
||||
public static class MvcBuilderExtensions
|
||||
{
|
||||
public static IMvcBuilder AddOpenHarborDynamicQueries(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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<IsAotCompatible>false</IsAotCompatible>
|
||||
<LangVersion>14</LangVersion>
|
||||
<Company>Svrnty</Company>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/svrnty/dotnet-cqrs</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
|
||||
<DebugType>portable</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\icon.png" Pack="true" PackagePath="" CopyToOutputDirectory="Always" />
|
||||
<None Include="..\README.md" Pack="true" PackagePath="" CopyToOutputDirectory="Always" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Svrnty.CQRS.Abstractions\Svrnty.CQRS.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Svrnty.CQRS.AspNetCore.Abstractions\Svrnty.CQRS.AspNetCore.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Svrnty.CQRS.DynamicQuery.Abstractions\Svrnty.CQRS.DynamicQuery.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Svrnty.CQRS.DynamicQuery\Svrnty.CQRS.DynamicQuery.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user