Fix episodes count calculation on dapper

This commit is contained in:
Zoe Roux 2023-12-04 22:57:57 +01:00
parent e70174cb24
commit 0bc6512bcc
5 changed files with 29 additions and 19 deletions

View File

@ -137,7 +137,7 @@ namespace Kyoo.Abstractions.Models
from from
episodes as e episodes as e
where where
e.season_id = id) as episode_count e.season_id = id) as episodes_count
""" """
)] )]
public int EpisodesCount { get; set; } public int EpisodesCount { get; set; }

View File

@ -179,10 +179,22 @@ namespace Kyoo.Abstractions.Models
.FirstOrDefault(); .FirstOrDefault();
/// <summary> /// <summary>
/// The number of episodes in this season. /// The number of episodes in this show.
/// </summary> /// </summary>
[Projectable(UseMemberBody = nameof(_EpisodesCount), OnlyOnInclude = true)] [Projectable(UseMemberBody = nameof(_EpisodesCount), OnlyOnInclude = true)]
[NotMapped] [NotMapped]
[LoadableRelation(
// language=PostgreSQL
Projected = """
(
select
count(*)::int
from
episodes as e
where
e.show_id = "this".id) as episodes_count
"""
)]
public int EpisodesCount { get; set; } public int EpisodesCount { get; set; }
private int _EpisodesCount => Episodes!.Count; private int _EpisodesCount => Episodes!.Count;

View File

@ -204,13 +204,14 @@ public static class DapperHelper
return $"\nwhere {Process(filter)}"; return $"\nwhere {Process(filter)}";
} }
public static string ExpendProjections(string type, string? prefix, Include include) public static string ExpendProjections(Type type, string? prefix, Include include)
{ {
IEnumerable<string> projections = include.Metadatas IEnumerable<string> projections = include.Metadatas
.Select(x => x is Include.ProjectedRelation(var name, var sql) ? sql : null!) .Select(x => (x as Include.ProjectedRelation)!)
.Where(x => x != null) .Where(x => x != null)
.Select(x => x.Replace("\"this\".", prefix)); .Where(x => type.GetProperty(x.Name) != null)
return string.Join(string.Empty, projections.Select(x => $", {x}")); .Select(x => x.Sql.Replace("\"this\".", prefix));
return string.Join(", ", projections);
} }
public static async Task<ICollection<T>> Query<T>( public static async Task<ICollection<T>> Query<T>(
@ -265,18 +266,20 @@ public static class DapperHelper
string? prefix = match.Groups[4].Value; string? prefix = match.Groups[4].Value;
prefix = !string.IsNullOrEmpty(prefix) ? $"{prefix}." : string.Empty; prefix = !string.IsNullOrEmpty(prefix) ? $"{prefix}." : string.Empty;
Type typeV = types.First(x => x.Name == type);
// Only project top level items with explicit includes. // Only project top level items with explicit includes.
string? projection = config.Any(x => x.Value.Name == type) string? projection = config.Any(x => x.Value.Name == type)
? ExpendProjections(type, prefix, include) ? ExpendProjections(typeV, prefix, include)
: null; : null;
Type? typeV = types.FirstOrDefault(x => x.Name == type);
if (typeV?.IsAssignableTo(typeof(IThumbnails)) == true) if (typeV.IsAssignableTo(typeof(IThumbnails)))
{ {
string posterProj = string.Join(", ", new[] { "poster", "thumbnail", "logo" } string posterProj = string.Join(", ", new[] { "poster", "thumbnail", "logo" }
.Select(x => $"{prefix}{x}_source as source, {prefix}{x}_blurhash as blurhash")); .Select(x => $"{prefix}{x}_source as source, {prefix}{x}_blurhash as blurhash"));
projection = string.IsNullOrEmpty(projection) projection = string.IsNullOrEmpty(projection)
? posterProj ? posterProj
: $"{posterProj}, {projection}"; : $"{projection}, {posterProj}";
types.InsertRange(types.IndexOf(typeV) + 1, Enumerable.Repeat(typeof(Image), 3)); types.InsertRange(types.IndexOf(typeV) + 1, Enumerable.Repeat(typeof(Image), 3));
} }

View File

@ -19,7 +19,6 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;

View File

@ -89,14 +89,6 @@ export const ShowP = withImages(
* The studio that made this show. * The studio that made this show.
*/ */
studio: StudioP.optional().nullable(), studio: StudioP.optional().nullable(),
/**
* The collection this movie is part of.
*/
collections: z.array(CollectionP).optional(),
/**
* The list of seasons of this show.
*/
seasons: z.array(SeasonP).optional(),
/** /**
* The first episode of this show * The first episode of this show
*/ */
@ -109,6 +101,10 @@ export const ShowP = withImages(
* Metadata of what an user as started/planned to watch. * Metadata of what an user as started/planned to watch.
*/ */
watchStatus: ShowWatchStatusP.nullable().optional(), watchStatus: ShowWatchStatusP.nullable().optional(),
/**
* The number of episodes in this show.
*/
episodesCount: z.number().int().gte(0).optional(),
}), }),
"shows", "shows",
) )