using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using Luticate2.Auth.Utils.Business.Converters; using Luticate2.Auth.Utils.Business.Converters.ExpressionConverter; using Luticate2.Auth.Utils.Dbo; using Luticate2.Auth.Utils.Dbo.Fields; using Luticate2.Auth.Utils.Dbo.Pagination; using Luticate2.Auth.Utils.Dbo.Result; using Luticate2.Auth.Utils.Interfaces; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; namespace Luticate2.Auth.Utils.DataAccess.Crud { public class LuEfCrudDataAccess : ILuCrud where TModel : class where TDbContext : DbContext where TDbo : class { protected IServiceProvider ServiceProvider { get; } protected ILuConvertersAllocator ConvertersAllocator { get; } protected ILuConvertersTypeConverter ConvertersTypeConverter { get; } public LuEfCrudDataAccess(IServiceProvider serviceProvider) { ServiceProvider = serviceProvider; ConvertersAllocator = ServiceProvider.GetRequiredService(); ConvertersTypeConverter = ServiceProvider.GetRequiredService(); } protected virtual LuConvertersOptions GetOptions() { return new LuConvertersOptions { Allocator = ConvertersAllocator, Parameters = new Dictionary(), TypeConverter = ConvertersTypeConverter };// TODO } protected virtual LuResult ConvertDboToModel(LuPartialFieldsDbo partialInput, TDbo dbo) { var copier = ServiceProvider.GetService>(); if (copier == null) { return LuResult.Error(LuStatus.InternalError.ToInt(), $"Could not get service: {nameof(ILuObjectConverter)}<{typeof(TDbo).Name}, {typeof(TModel).Name}>"); } var options = GetOptions(); var dstObjResult = options.Allocator.GetInstance(typeof(TModel)); if (!dstObjResult) { return dstObjResult.To(); } var dstObj = dstObjResult.Data; var result = copier.Convert(dbo, dstObj, new LuFieldDbo(), partialInput, GetOptions()); return result.Select(o => o as TModel); } protected virtual LuResult ConvertModelToDbo(LuPartialFieldsDbo partialResponse, TModel model) { var copier = ServiceProvider.GetService>(); if (copier == null) { return LuResult.Error(LuStatus.InternalError.ToInt(), $"Could not get service: {nameof(ILuObjectConverter)}<{typeof(TModel).Name}, {typeof(TDbo).Name}>"); } var options = GetOptions(); var dstObjResult = options.Allocator.GetInstance(typeof(TDbo)); if (!dstObjResult) { return dstObjResult.To(); } var dstObj = dstObjResult.Data; var result = copier.Convert(model, dstObj, new LuFieldDbo(), partialResponse, GetOptions()); return result.Select(o => o as TDbo); } protected virtual LuResult HandleError(Exception e) { return LuResult.Error(LuStatus.DbError.ToInt(), e); } protected LuResult Execute(Func, LuResult> action) { try { using (var db = ServiceProvider.GetService()) { return action(db, db.Set()); } } catch (Exception e) { var result = HandleError(e); return result; } } protected virtual LuResult> Include(LuPartialFieldsDbo partialResponse, IQueryable queryable) { return LuResult>.Ok(queryable); } protected virtual LuResult> Filter(LuFilterDbo filter, IQueryable queryable) { if (filter.Expression == null) { return LuResult>.Ok(queryable); } var lamdbaDbo = (Expression>) filter.Expression; var options = GetOptions(); var converter = new LuExpressionConverterVisitor(options, ServiceProvider); var lamdbaModel = converter.Visit(lamdbaDbo) as Expression>;// TODO Handle errors return LuResult>.Ok(queryable.Where(lamdbaModel)); } protected virtual LuResult> OrderByField(LuOrderByFieldDbo orderByField, IQueryable queryable) { var lamdbaDbo = (Expression>) orderByField.Expression; var options = GetOptions(); var converter = new LuExpressionConverterVisitor(options, ServiceProvider); var lamdbaModel = converter.Visit(lamdbaDbo) as Expression>; IOrderedQueryable ordered = null; if (queryable is IOrderedQueryable orderedQueryable) { if (orderByField.Asc) { ordered = orderedQueryable.ThenBy(lamdbaModel); } else { ordered = orderedQueryable.ThenByDescending(lamdbaModel); } } else { if (orderByField.Asc) { ordered = queryable.OrderBy(lamdbaModel); } else { ordered = queryable.OrderByDescending(lamdbaModel); } } return LuResult>.Ok(ordered); // var expressionBuilder = ServiceProvider.GetService>(); // var expressionResult = expressionBuilder.ConvertLamdba(orderByfield.); // if (!expressionResult) // { // return expressionResult.To>(); // } // // var expression = expressionResult.Data; // var expressionNoConvert = LuExpressionUtils.GetFromConvert(expression); // // var ordered = queryable.OrderBy(expressionNoConvert); // // return LuResult>.Ok(ordered); // return LuResult>.Ok(queryable); } protected virtual LuResult> OrderBy(LuOrderByDbo orderBy, IQueryable queryable) { var ordered = queryable; foreach (var field in orderBy.OrderByFields) { var orderedResult = OrderByField(field, ordered); if (!orderedResult) { return orderedResult.To>(); } ordered = orderedResult.Data; } return LuResult>.Ok(ordered ?? queryable); } protected virtual LuResult> Paginate(int page, int perPage, IQueryable queryable) { var paginated = queryable.Skip(page * perPage).Take(perPage); return LuResult>.Ok(paginated); } public virtual LuResult> Create(LuPartialFieldsDbo partialResponse, LuPartialFieldsDbo partialInput, IEnumerable dbos) { throw new NotImplementedException(); } public virtual LuResult> Read(LuPartialFieldsDbo partialResponse, LuPaginatedParamsDbo paginationParams) { var result = Execute((context, set) => { var includeResult = Include(partialResponse, set); if (!includeResult) { return includeResult.To>(); } var included = includeResult.Data; var orderByResult = OrderBy(paginationParams.OrderBy, included); if (!orderByResult) { return orderByResult.To>(); } var ordered = orderByResult.Data; var filteredResult = Filter(paginationParams.Filter, ordered); if (!filteredResult) { return filteredResult.To>(); } var filtered = filteredResult.Data; var count = filtered.Count(); var paginatedResult = Paginate(paginationParams.Page, paginationParams.PerPage, filtered); if (!paginatedResult) { return paginatedResult.To>(); } var paginated = paginatedResult.Data; var data = paginated.AsEnumerable().Select(model => { var convertResult = ConvertModelToDbo(partialResponse, model); // TODO Handle error return convertResult.Data; }).ToList(); return LuResult>.Ok(new LuPaginatedDbo { Count = count, Data = data }); }); return result; } public virtual LuResult> Update(LuPartialFieldsDbo partialResponse, LuPartialFieldsDbo partialInput, IEnumerable dbos) { throw new NotImplementedException(); } public virtual LuResult> Delete(LuPartialFieldsDbo partialResponse, LuPartialFieldsDbo partialInput, IEnumerable dbos) { throw new NotImplementedException(); } } }