mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-30 19:54:16 -04:00
Implementing a basic query parser for where, sort & pagination
This commit is contained in:
parent
3443e102e9
commit
ea625fa45b
@ -31,6 +31,27 @@ namespace Kyoo.Controllers
|
|||||||
Key = key;
|
Key = key;
|
||||||
Descendant = descendant;
|
Descendant = descendant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Sort(string sortBy)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(sortBy))
|
||||||
|
{
|
||||||
|
Key = null;
|
||||||
|
Descendant = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string key = sortBy.Contains(':') ? sortBy.Substring(0, sortBy.IndexOf(':')) : sortBy;
|
||||||
|
string order = sortBy.Contains(':') ? sortBy.Substring(sortBy.IndexOf(':') + 1) : null;
|
||||||
|
|
||||||
|
Key = Expression.Lambda<Func<T, object>>(Expression.Property(Expression.Parameter(typeof(T), "x"), key));
|
||||||
|
Descendant = order switch
|
||||||
|
{
|
||||||
|
"desc" => true,
|
||||||
|
"asc" => false,
|
||||||
|
_ => throw new ArgumentException($"The sort order, if set, should be :asc or :desc but it was :{order}.")
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IRepository<T> : IDisposable, IAsyncDisposable
|
public interface IRepository<T> : IDisposable, IAsyncDisposable
|
||||||
|
@ -236,5 +236,49 @@ namespace Kyoo
|
|||||||
|
|
||||||
return member.Member.Name;
|
return member.Member.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Expression<Func<T, bool>> ParseWhere<T>(Dictionary<string, string> where)
|
||||||
|
{
|
||||||
|
if (where == null || where.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ParameterExpression param = Expression.Parameter(typeof(T));
|
||||||
|
Expression expression = null;
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, string> cond in where)
|
||||||
|
{
|
||||||
|
string value = cond.Value;
|
||||||
|
string operand = "eq";
|
||||||
|
if (value.Contains(':'))
|
||||||
|
{
|
||||||
|
operand = value.Substring(0, value.IndexOf(':'));
|
||||||
|
value = value.Substring(value.IndexOf(':') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyInfo valueParam = typeof(T).GetProperty(cond.Key); // TODO get this property with case insensitive.
|
||||||
|
// TODO throw if valueParam is null.
|
||||||
|
MemberExpression property = Expression.Property(param, valueParam);
|
||||||
|
ConstantExpression condValue = Expression.Constant(value); // TODO Cast this to the right type (take nullable into account).
|
||||||
|
|
||||||
|
Expression condition = operand switch
|
||||||
|
{
|
||||||
|
"eq" => Expression.Equal(property, condValue),
|
||||||
|
"not" => Expression.NotEqual(property, condValue),
|
||||||
|
"lt" => Expression.LessThan(property, condValue),
|
||||||
|
"lte" => Expression.LessThanOrEqual(property, condValue),
|
||||||
|
"gt" => Expression.GreaterThan(property, condValue),
|
||||||
|
"gte" => Expression.GreaterThanOrEqual(property, condValue),
|
||||||
|
"like" => throw new NotImplementedException("Like not implemented yet"),
|
||||||
|
_ => throw new ArgumentException($"Invalid operand: {operand}")
|
||||||
|
};
|
||||||
|
|
||||||
|
if (expression != null)
|
||||||
|
expression = Expression.AndAlso(expression, condition);
|
||||||
|
else
|
||||||
|
expression = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Expression.Lambda<Func<T, bool>>(expression!);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -75,7 +75,25 @@ namespace Kyoo.Controllers
|
|||||||
Sort<Show> sort = default,
|
Sort<Show> sort = default,
|
||||||
Pagination page = default)
|
Pagination page = default)
|
||||||
{
|
{
|
||||||
return await _database.Shows.ToListAsync();
|
IQueryable<Show> query = _database.Shows;
|
||||||
|
|
||||||
|
if (where != null)
|
||||||
|
query = query.Where(where);
|
||||||
|
|
||||||
|
Expression<Func<Show, object>> sortKey = sort.Key ?? (x => x.Title);
|
||||||
|
query = sort.Descendant ? query.OrderByDescending(sortKey) : query.OrderBy(sortKey);
|
||||||
|
|
||||||
|
if (page.AfterID != 0)
|
||||||
|
{
|
||||||
|
Show after = await Get(page.AfterID);
|
||||||
|
object afterObj = sortKey.Compile()(after);
|
||||||
|
query = query.Where(Expression.Lambda<Func<Show, bool>>(
|
||||||
|
Expression.GreaterThan(sortKey, Expression.Constant(afterObj))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
query = query.Take(page.Count <= 0 ? 20 : page.Count);
|
||||||
|
|
||||||
|
return await query.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> Create(Show obj)
|
public async Task<int> Create(Show obj)
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
using Kyoo.Models;
|
using System;
|
||||||
|
using Kyoo.Models;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Castle.DynamicProxy.Generators.Emitters.SimpleAST;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -35,12 +38,14 @@ namespace Kyoo.Api
|
|||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Authorize(Policy="Read")]
|
[Authorize(Policy="Read")]
|
||||||
public IEnumerable<Show> GetShows()
|
public async Task<IEnumerable<Show>> GetShows([FromQuery] string sortBy,
|
||||||
|
[FromQuery] int limit,
|
||||||
|
[FromQuery] int afterID,
|
||||||
|
[FromQuery] Dictionary<string, string> where)
|
||||||
{
|
{
|
||||||
return _database.LibraryLinks
|
return await _libraryManager.GetShows(Utility.ParseWhere<Show>(where),
|
||||||
.Include(x => x.Show)
|
new Sort<Show>(sortBy),
|
||||||
.Include(x => x.Collection)
|
new Pagination(limit, afterID));
|
||||||
.AsEnumerable().Select(x => x.Show ?? x.Collection.AsShow()).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{slug}")]
|
[HttpGet("{slug}")]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user