Use new filter in dapper

This commit is contained in:
Zoe Roux 2023-11-24 00:18:59 +01:00
parent edc6d11824
commit 3eff6228be
3 changed files with 40 additions and 15 deletions

View File

@ -177,7 +177,7 @@ namespace Kyoo.Core.Controllers
return (retConfig, join.ToString(), Map); return (retConfig, join.ToString(), Map);
} }
public static string ExpendProjections<T>(string? prefix, Include include) public static FormattableString ExpendProjections<T>(string? prefix, Include include)
{ {
prefix = prefix != null ? $"{prefix}." : string.Empty; prefix = prefix != null ? $"{prefix}." : string.Empty;
IEnumerable<string> projections = include.Metadatas IEnumerable<string> projections = include.Metadatas
@ -185,18 +185,40 @@ namespace Kyoo.Core.Controllers
.Where(x => x != null) .Where(x => x != null)
.Select(x => x.Replace("\"this\".", prefix)); .Select(x => x.Replace("\"this\".", prefix));
string projStr = string.Join(string.Empty, projections.Select(x => $", {x}")); string projStr = string.Join(string.Empty, projections.Select(x => $", {x}"));
return $"{prefix}*" + projStr; return $"{prefix:raw}*{projStr:raw}";
} }
public static string ProcessFilter<T>(Filter<T> filter, Dictionary<string, Type> config) public static FormattableString ProcessFilter<T>(Filter<T> filter, Dictionary<string, Type> config)
{ {
return filter switch FormattableString Format(string key, FormattableString op)
{ {
Filter<T>.And(var first, var second) => $"({ProcessFilter(first, config)} and {ProcessFilter(second, config)})", IEnumerable<string> properties = config
Filter<T>.Or(var first, var second) => $"({ProcessFilter(first, config)} or {ProcessFilter(second, config)})", .Where(x => key == "id" || x.Value.GetProperty(key) != null)
Filter<T>.Not(var inner) => $"(not {ProcessFilter(inner, config)})", .Select(x => $"{x.Key}.{x.Value.GetProperty(key)?.GetCustomAttribute<ColumnAttribute>()?.Name ?? key.ToSnakeCase()}");
Filter<T>.Eq(var property, var value) => $"({_Property(property, config)} = {value})",
}; FormattableString ret = $"{properties.First():raw} {op}";
foreach (string property in properties.Skip(1))
ret = $"{ret} or {property:raw} {op}";
return $"({ret})";
}
FormattableString Process(Filter<T> fil)
{
return fil switch
{
Filter<T>.And(var first, var second) => $"({Process(first)} and {Process(second)})",
Filter<T>.Or(var first, var second) => $"({Process(first)} or {Process(second)})",
Filter<T>.Not(var inner) => $"(not {Process(inner)})",
Filter<T>.Eq(var property, var value) => Format(property, $"= {value}"),
Filter<T>.Ne(var property, var value) => Format(property, $"!= {value}"),
Filter<T>.Gt(var property, var value) => Format(property, $"> {value}"),
Filter<T>.Ge(var property, var value) => Format(property, $">= {value}"),
Filter<T>.Lt(var property, var value) => Format(property, $"< {value}"),
Filter<T>.Le(var property, var value) => Format(property, $"> {value}"),
Filter<T>.Lambda(var lambda) => throw new NotSupportedException(),
};
}
return $"where {Process(filter)}";
} }
public async Task<ICollection<ILibraryItem>> GetAll(Filter<ILibraryItem>? filter = null, public async Task<ICollection<ILibraryItem>> GetAll(Filter<ILibraryItem>? filter = null,
@ -217,7 +239,7 @@ namespace Kyoo.Core.Controllers
// language=PostgreSQL // language=PostgreSQL
var query = _database.SqlBuilder($""" var query = _database.SqlBuilder($"""
select select
{ExpendProjections<Show>("s", include):raw}, {ExpendProjections<Show>("s", include)},
m.*, m.*,
c.* c.*
{string.Join(string.Empty, includeConfig.Select(x => $", {x.Key}.*")):raw} {string.Join(string.Empty, includeConfig.Select(x => $", {x.Key}.*")):raw}
@ -225,21 +247,21 @@ namespace Kyoo.Core.Controllers
shows as s shows as s
full outer join ( full outer join (
select select
{ExpendProjections<Movie>(null, include):raw} {ExpendProjections<Movie>(null, include)}
from from
movies) as m on false movies) as m on false
full outer join ( full outer join (
select select
{ExpendProjections<Collection>(null, include):raw} {ExpendProjections<Collection>(null, include)}
from from
collections) as c on false collections) as c on false
{includeJoin:raw} {includeJoin:raw}
order by {ProcessSort(sort, config):raw}
limit {limit.Limit}
"""); """);
if (filter != null) if (filter != null)
query += $"where {ProcessFilter(filter, config):raw}"; query += ProcessFilter(filter, config);
query += $"order by {ProcessSort(sort, config):raw}";
query += $"limit {limit.Limit}";
Type[] types = config.Select(x => x.Value) Type[] types = config.Select(x => x.Value)
.Concat(includeConfig.Select(x => x.Value)) .Concat(includeConfig.Select(x => x.Value))

View File

@ -9,6 +9,7 @@
<PackageReference Include="Dapper" Version="2.1.21" /> <PackageReference Include="Dapper" Version="2.1.21" />
<PackageReference Include="EFCore.NamingConventions" Version="7.0.2" /> <PackageReference Include="EFCore.NamingConventions" Version="7.0.2" />
<PackageReference Include="EntityFrameworkCore.Projectables" Version="4.1.4-prebeta" /> <PackageReference Include="EntityFrameworkCore.Projectables" Version="4.1.4-prebeta" />
<PackageReference Include="InterpolatedSql.Dapper" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.12"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.12">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Data.Common; using System.Data.Common;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Dapper; using Dapper;
using InterpolatedSql.SqlBuilders;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
using Kyoo.Postgresql.Utils; using Kyoo.Postgresql.Utils;
@ -87,6 +88,7 @@ namespace Kyoo.Postgresql
SqlMapper.AddTypeHandler(typeof(Dictionary<string, MetadataId>), new JsonTypeHandler<Dictionary<string, MetadataId>>()); SqlMapper.AddTypeHandler(typeof(Dictionary<string, MetadataId>), new JsonTypeHandler<Dictionary<string, MetadataId>>());
SqlMapper.AddTypeHandler(typeof(List<string>), new ListTypeHandler<string>()); SqlMapper.AddTypeHandler(typeof(List<string>), new ListTypeHandler<string>());
SqlMapper.AddTypeHandler(typeof(List<Genre>), new ListTypeHandler<Genre>()); SqlMapper.AddTypeHandler(typeof(List<Genre>), new ListTypeHandler<Genre>());
InterpolatedSqlBuilderOptions.DefaultOptions.ReuseIdenticalParameters = true;
} }
/// <inheritdoc /> /// <inheritdoc />