Creating an expression rewritter that work with members

This commit is contained in:
Zoe Roux 2020-09-11 00:35:21 +02:00
parent 8430f0f1d8
commit fb14eb4ef2
6 changed files with 56 additions and 24 deletions

View File

@ -30,7 +30,7 @@ namespace Kyoo.Controllers
public Sort(Expression<Func<T, object>> key, bool descendant = false) public Sort(Expression<Func<T, object>> key, bool descendant = false)
{ {
Key = key; Key = ExpressionRewrite.Rewrite<Func<T, object>>(key);
Descendant = descendant; Descendant = descendant;
if (Key == null || if (Key == null ||
@ -58,6 +58,7 @@ namespace Kyoo.Controllers
Key = property.Type.IsValueType Key = property.Type.IsValueType
? Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param) ? Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param)
: Expression.Lambda<Func<T, object>>(property, param); : Expression.Lambda<Func<T, object>>(property, param);
Key = ExpressionRewrite.Rewrite<Func<T, object>>(Key);
Descendant = order switch Descendant = order switch
{ {

View File

@ -0,0 +1,46 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace Kyoo
{
public class ExpressionRewriteAttribute : Attribute
{
public string Link { get; }
public string Inner { get; }
public ExpressionRewriteAttribute(string link, string inner = null)
{
Link = link;
Inner = inner;
}
}
public class ExpressionRewrite : ExpressionVisitor
{
public static Expression Rewrite(Expression expression)
{
return new ExpressionRewrite().Visit(expression);
}
public static Expression<T> Rewrite<T>(Expression expression) where T : Delegate
{
return (Expression<T>)new ExpressionRewrite().Visit(expression);
}
protected override Expression VisitMember(MemberExpression node)
{
ExpressionRewriteAttribute attr = node.Member.GetCustomAttribute<ExpressionRewriteAttribute>();
if (attr == null)
return base.VisitMember(node);
Expression property = node.Expression;
foreach (string child in attr.Link.Split('.'))
property = Expression.Property(property, child);
if (property is MemberExpression member)
Visit(member.Expression);
return property;
}
}
}

View File

@ -11,12 +11,14 @@ namespace Kyoo.Models
[JsonIgnore] public int PeopleID { get; set; } [JsonIgnore] public int PeopleID { get; set; }
[JsonIgnore] public virtual People People { get; set; } [JsonIgnore] public virtual People People { get; set; }
[ExpressionRewrite(nameof(People) + "." + nameof(Models.People.Slug))]
public string Slug public string Slug
{ {
get => People.Slug; get => People.Slug;
set => People.Slug = value; set => People.Slug = value;
} }
[ExpressionRewrite(nameof(People) + "."+ nameof(Models.People.Name))]
public string Name public string Name
{ {
get => People.Name; get => People.Name;

View File

@ -71,8 +71,9 @@ namespace Kyoo.CommonApi
else else
expression = condition; expression = condition;
} }
return Expression.Lambda<Func<T, bool>>(expression!, param); expression = ExpressionRewrite.Rewrite(expression);
return Expression.Lambda<Func<T, bool>>(expression, param);
} }
private static Expression ContainsResourceExpression(MemberExpression xProperty, string value) private static Expression ContainsResourceExpression(MemberExpression xProperty, string value)

View File

@ -98,16 +98,6 @@ namespace Kyoo.Controllers
Sort<PeopleRole> sort = default, Sort<PeopleRole> sort = default,
Pagination limit = default) Pagination limit = default)
{ {
if (sort.Key?.Body is MemberExpression member)
{
sort.Key = member.Member.Name switch
{
"Name" => x => x.People.Name,
"Slug" => x => x.People.Slug,
_ => sort.Key
};
}
ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles.Where(x => x.ShowID == showID), ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles.Where(x => x.ShowID == showID),
id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id),
x => x.People.Name, x => x.People.Name,
@ -124,16 +114,6 @@ namespace Kyoo.Controllers
Sort<PeopleRole> sort = default, Sort<PeopleRole> sort = default,
Pagination limit = default) Pagination limit = default)
{ {
if (sort.Key?.Body is MemberExpression member)
{
sort.Key = member.Member.Name switch
{
"Name" => x => x.People.Name,
"Slug" => x => x.People.Slug,
_ => sort.Key
};
}
ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles.Where(x => x.Show.Slug == showSlug), ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles.Where(x => x.Show.Slug == showSlug),
id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id),
x => x.People.Name, x => x.People.Name,

View File

@ -15,7 +15,9 @@ namespace Kyoo.Models
} }
[JsonIgnore] [NotMergable] public virtual IEnumerable<LibraryLink> LibraryLinks { get; set; } [JsonIgnore] [NotMergable] public virtual IEnumerable<LibraryLink> LibraryLinks { get; set; }
/*[ExpressionRewrite(x => x.LibraryLinks, y => y.Genre)]*/ public override IEnumerable<Library> Libraries
[ExpressionRewrite(nameof(LibraryLinks), nameof(GenreLink.Genre))]
public override IEnumerable<Library> Libraries
{ {
get => LibraryLinks?.Select(x => x.Library); get => LibraryLinks?.Select(x => x.Library);
set => LibraryLinks = value?.Select(x => new LibraryLink(x, this)); set => LibraryLinks = value?.Select(x => new LibraryLink(x, this));