mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -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;
|
||||
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
|
||||
|
@ -236,5 +236,49 @@ namespace Kyoo
|
||||
|
||||
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,
|
||||
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)
|
||||
|
@ -1,8 +1,11 @@
|
||||
using Kyoo.Models;
|
||||
using System;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Castle.DynamicProxy.Generators.Emitters.SimpleAST;
|
||||
using Kyoo.Controllers;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -35,12 +38,14 @@ namespace Kyoo.Api
|
||||
|
||||
[HttpGet]
|
||||
[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
|
||||
.Include(x => x.Show)
|
||||
.Include(x => x.Collection)
|
||||
.AsEnumerable().Select(x => x.Show ?? x.Collection.AsShow()).ToList();
|
||||
return await _libraryManager.GetShows(Utility.ParseWhere<Show>(where),
|
||||
new Sort<Show>(sortBy),
|
||||
new Pagination(limit, afterID));
|
||||
}
|
||||
|
||||
[HttpGet("{slug}")]
|
||||
|
Loading…
x
Reference in New Issue
Block a user