using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
namespace adas_core.Domain;
///
/// Allow to pass to a
/// multiple requests like:
/// * Include (to fetch eagerly relations inside T entity)
/// Use a Builder pattern.
///
///
/// var queryCustomizer = QueryCustomizer<Video>.New()
/// .Include(v => v.Room)
/// .Include(v => v.Clips)
/// .Include(v => v.Diagnosis)
/// .Include(v => v.Movies)
/// .Include(v => v.Patient)
/// .Include(v => v.Service)
/// .Include(v => v.Thumbnail)
/// .Include(v => v.VideoDoctors)
/// .Include(v => v.Procedure)
/// .Include(v => v.Recordings)
/// .Include(v => v.Chapters)
/// .Include(v => v.LogDownloadVideoUsers)
/// .Include("VideoDoctors.Doctor")
/// ;
/// var v = _videoRepository.GetById(id, queryCustomizer);
///
///
///
public class QueryCustomizer where T : class
{
private readonly List>> _includeLinqExpressions = [];
private readonly List _includeLinqStringExpressions = [];
///
/// Creates and returns a new instance of the class.
///
/// A new instance.
public static QueryCustomizer New()
{
return new QueryCustomizer();
}
///
/// Adds a related entity to the set of include expressions used by the query, enabling eager loading of the specified navigation property.
///
/// A lambda expression selecting the related entity to include in the query results.
/// The current instance to allow fluent chaining of additional includes or customizations.
public QueryCustomizer Include(Expression> includeExpression)
{
_includeLinqExpressions.Add(includeExpression);
return this;
}
///
/// Adds one or more include expressions to the query customizer, enabling eager loading of related entities in the resulting query.
///
/// The expressions specifying the related entities to include in the query.
/// The current instance to support fluent method chaining.
public QueryCustomizer Include(params Expression>[] includeExpressions)
{
_includeLinqExpressions.AddRange(includeExpressions);
return this;
}
///
/// Adds an include expression to the customizer, typically used to specify related entities to eager-load in the query, and returns the current instance to support fluent chaining.
///
/// The include expression to be added to the collection of include expressions.
/// The current instance with the include expression added.
public QueryCustomizer Include(string includeExpression)
{
_includeLinqStringExpressions.Add(includeExpression);
return this;
}
///
/// Adds the specified include expressions to the query, allowing additional related entities or navigation properties to be loaded alongside the primary result.
///
/// The string expressions representing the related entities or paths to include in the query.
/// The current instance to enable fluent method chaining.
public QueryCustomizer Include(params string[] includeExpressions)
{
_includeLinqStringExpressions.AddRange(includeExpressions);
return this;
}
///
/// Applies a sequence of Include expressions to the specified queryable, enabling eager loading of related entities.
/// Includes are applied in two passes: first using the pre-built LINQ expressions, then using the string-based include expressions.
///
/// The source queryable to which the include expressions will be applied.
/// An with all configured include expressions applied.
public IQueryable AddToQueryable(IQueryable queryable)
{
var resultQueryable = queryable;
resultQueryable = _includeLinqExpressions
.Aggregate(resultQueryable, (current, expression) => current.Include(expression))
;
resultQueryable = _includeLinqStringExpressions
.Aggregate(resultQueryable, (current, expression) => current.Include(expression))
;
return resultQueryable;
}
}