196 lines
8.2 KiB
C#
196 lines
8.2 KiB
C#
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using ApiSourceGeneratorHelper;
|
|
using AutoMapPropertyHelper;
|
|
using EntityFrameworkCore.Projectables;
|
|
using EntityFrameworkCore.Projectables.Extensions;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Http.HttpResults;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using NejCommon.Utils;
|
|
using Swashbuckle.AspNetCore.Annotations;
|
|
using NejCommon.Models;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace NejCommon.Controllers
|
|
{
|
|
|
|
public abstract class AutoController<TOwner, TType, TRequest, TResponse> : AutoController<TOwner, TType, TResponse, TRequest, TResponse, TResponse, TRequest, TResponse>
|
|
where TType : class
|
|
where TRequest : class, IAutomappedAttribute<TType, TRequest>, new()
|
|
where TResponse : class, IAutomappedAttribute<TType, TResponse>, new()
|
|
{
|
|
public AutoController(CommonDbContext appDb, IServiceProvider providers) : base(appDb, providers)
|
|
{
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <typeparam name="TType">The underyling type</typeparam>
|
|
/// <typeparam name="TRequest">The request type</typeparam>
|
|
/// <typeparam name="TResponse">The response type</typeparam>
|
|
[ApiController]
|
|
public abstract partial class AutoController<TOwner, TType, TGetAllResponse, TCreateRequest, TCreateResponse, TGetResponse, TUpdateRequest, TUpdateResponse> : AutoGetterController<TOwner, TType, TGetAllResponse, TGetResponse>
|
|
where TType : class
|
|
where TGetAllResponse : class, IAutomappedAttribute<TType, TGetAllResponse>, new()
|
|
where TCreateRequest : class, IAutomappedAttribute<TType, TCreateRequest>, new()
|
|
where TCreateResponse : class, IAutomappedAttribute<TType, TCreateResponse>, new()
|
|
where TGetResponse : class, IAutomappedAttribute<TType, TGetResponse>, new()
|
|
where TUpdateRequest : class, IAutomappedAttribute<TType, TUpdateRequest>, new()
|
|
where TUpdateResponse : class, IAutomappedAttribute<TType, TUpdateResponse>, new()
|
|
{
|
|
|
|
public AutoController(CommonDbContext appDb, IServiceProvider providers) : base(appDb, providers)
|
|
{
|
|
|
|
}
|
|
|
|
protected virtual TType AssociateWithParent(TType entity, TOwner comp)
|
|
{
|
|
var props = typeof(TType).GetProperty(HelperMainName);
|
|
if (props == null)
|
|
{
|
|
//not implemented
|
|
throw new NotImplementedException("Special parent association not implemented");
|
|
}
|
|
props.SetValue(entity, comp);
|
|
return entity;
|
|
}
|
|
protected override IAutomappedAttribute GetResponseType(RequestedResponseType type, TType entity) => type switch
|
|
{
|
|
RequestedResponseType.Create => new TCreateResponse(),
|
|
RequestedResponseType.Update => new TUpdateResponse(),
|
|
_ => base.GetResponseType(type, entity),
|
|
};
|
|
|
|
/// <summary>
|
|
/// Creates the <typeparamref name="TType"/>
|
|
/// </summary>
|
|
/// <param name="body"></param>
|
|
/// <response code="201">Success</response>
|
|
/// <response code="0">There was an error</response>
|
|
[HttpPost]
|
|
public virtual async Task<Results<BadRequest<Error>, CreatedAtRoute<TCreateResponse>>> Create([FromServices] TOwner company, [FromBody] TCreateRequest body)
|
|
{
|
|
var type = body.GetSourceType();
|
|
var entity = (TType)db.Create(type);
|
|
|
|
entity = AssociateWithParent(entity, company);
|
|
|
|
await db.AddAsync(entity);
|
|
|
|
body.ApplyTo(providers, (object)entity);
|
|
|
|
return await db.ApiSaveChangesAsyncCreate<TType, TCreateResponse>(providers, entity, true, (TCreateResponse)GetResponseType(RequestedResponseType.Create, entity));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delete company.
|
|
/// </summary>
|
|
/// <param name="entity"></param>
|
|
/// <response code="200">Success</response>
|
|
/// <response code="0">There was an error</response>
|
|
[HttpDelete]
|
|
[Route("{id}/")]
|
|
public virtual async Task<Results<BadRequest<Error>, Ok>> Delete([FromServices][ModelBinder(Name = "id")] TType entity)
|
|
{
|
|
db.Remove(entity!);
|
|
|
|
return await db.ApiSaveChangesAsync(TypedResults.Ok());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update company.
|
|
/// </summary>
|
|
/// <param name="entity"></param>
|
|
/// <param name="body"></param>
|
|
/// <response code="200">Success</response>
|
|
/// <response code="0">There was an error</response>
|
|
[HttpPut]
|
|
[Route("{id}/")]
|
|
public virtual async Task<Results<NotFound, BadRequest<Error>, Ok<TUpdateResponse>>> Update([FromServices][ModelBinder(Name = "id")] TType entity, [FromBody] TUpdateRequest body)
|
|
{
|
|
body.ApplyTo(providers, (object)entity);
|
|
|
|
var dat = new TUpdateResponse().ApplyFrom(providers, entity);
|
|
|
|
var res = await db.ApiSaveChangesAsyncOk<TType, TUpdateResponse>(providers, entity, true, (TUpdateResponse)GetResponseType(RequestedResponseType.Update, entity));
|
|
|
|
//use the private constructor thru reflection
|
|
var ctor = typeof(Results<NotFound, BadRequest<Error>, Ok<TUpdateResponse>>).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
|
|
return (Results<NotFound, BadRequest<Error>, Ok<TUpdateResponse>>)ctor.Invoke(new object[] { res.Result });
|
|
}
|
|
}
|
|
[ApiController]
|
|
public abstract class AutoGetterController<TOwner, TType, TGetAllResponse, TGetResponse> : ControllerBase
|
|
where TType : class
|
|
where TGetAllResponse : IAutomappedAttribute<TType, TGetAllResponse>, new()
|
|
where TGetResponse : IAutomappedAttribute<TType, TGetResponse>, new()
|
|
{
|
|
protected readonly CommonDbContext db;
|
|
protected readonly IServiceProvider providers;
|
|
|
|
public AutoGetterController(CommonDbContext appDb, IServiceProvider providers) : base()
|
|
{
|
|
db = appDb;
|
|
this.providers = providers;
|
|
}
|
|
|
|
protected abstract IQueryable<TType> GetQuery(TOwner comp);
|
|
|
|
public enum RequestedResponseType
|
|
{
|
|
Get,
|
|
Create,
|
|
Update
|
|
}
|
|
protected virtual IAutomappedAttribute GetResponseType(RequestedResponseType type, TType entity) => type switch
|
|
{
|
|
RequestedResponseType.Get => new TGetResponse(),
|
|
_ => throw new InvalidOperationException("Not implemented"),
|
|
};
|
|
|
|
protected virtual IQueryable<TType> ApplyDefaultOrdering(IQueryable<TType> query)
|
|
{
|
|
return query;
|
|
}
|
|
|
|
protected virtual Task<PaginationResponse<TGetAllResponse>> ApplyPagination(IQueryable<TType> query, Pagination pag, CancellationToken cancellationToken = default)
|
|
{
|
|
return query.ApplyPaginationRes<TType, TGetAllResponse>(providers, pag, cancellationToken: cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get all the <typeparamref name="TType"/>
|
|
/// </summary>
|
|
/// <response code="200">Success</response>
|
|
/// <response code="0">There was an error</response>
|
|
[HttpGet]
|
|
public virtual async Task<Results<BadRequest<Error>, Ok<PaginationResponse<TGetAllResponse>>>> GetAll([FromServices] TOwner company, [FromQuery] Pagination pag, CancellationToken cancellationToken)
|
|
{
|
|
var data = await ApplyPagination(ApplyDefaultOrdering(GetQuery(company)).AsNoTrackingWithIdentityResolution(), pag, cancellationToken);
|
|
|
|
//Console.Writeline(data.Data);
|
|
|
|
return TypedResults.Ok(data);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the <typeparamref name="TType"/>
|
|
/// </summary>
|
|
/// <param name="entity"></param>
|
|
/// <response code="200">Success</response>
|
|
/// <response code="0">There was an error</response>
|
|
[HttpGet]
|
|
[Route("{id}/")]
|
|
public virtual async Task<Results<NotFound, Ok<TGetResponse>>> Get([FromServices][ModelBinder(Name = "id")] TType entity)
|
|
{
|
|
var dat = GetResponseType(RequestedResponseType.Get, entity).ApplyFrom(providers, entity);
|
|
return TypedResults.Ok((TGetResponse)dat);
|
|
}
|
|
}
|
|
}
|