From eed058c89108152612ef60a44be3e687573f6441 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 20 Nov 2023 03:23:55 +0100 Subject: [PATCH] Disables many to many eager includes --- .../Attributes/EditableRelationAttribute.cs | 29 ------------ .../Models/Resources/Collection.cs | 4 +- .../Models/Resources/Movie.cs | 6 +-- .../Models/Resources/People.cs | 2 +- .../Models/Resources/Season.cs | 2 +- .../Models/Resources/Show.cs | 10 ++--- .../Models/Resources/Studio.cs | 4 +- .../Kyoo.Abstractions/Models/Utils/Include.cs | 17 +++++-- front/packages/ui/src/details/collection.tsx | 44 ++++++++++++++++++- front/packages/ui/src/details/header.tsx | 13 ------ front/packages/ui/src/details/movie.tsx | 5 ++- front/packages/ui/src/details/show.tsx | 3 ++ 12 files changed, 77 insertions(+), 62 deletions(-) delete mode 100644 back/src/Kyoo.Abstractions/Models/Attributes/EditableRelationAttribute.cs diff --git a/back/src/Kyoo.Abstractions/Models/Attributes/EditableRelationAttribute.cs b/back/src/Kyoo.Abstractions/Models/Attributes/EditableRelationAttribute.cs deleted file mode 100644 index a94f401b..00000000 --- a/back/src/Kyoo.Abstractions/Models/Attributes/EditableRelationAttribute.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System; -using Kyoo.Abstractions.Controllers; - -namespace Kyoo.Abstractions.Models.Attributes -{ - /// - /// The targeted relation can be edited via calls to the repository's method. - /// - [AttributeUsage(AttributeTargets.Property)] - public class EditableRelationAttribute : Attribute { } -} diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs index 771050ef..eb1bac26 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs @@ -64,12 +64,12 @@ namespace Kyoo.Abstractions.Models /// /// The list of movies contained in this collection. /// - [LoadableRelation] public ICollection? Movies { get; set; } + [SerializeIgnore] public ICollection? Movies { get; set; } /// /// The list of shows contained in this collection. /// - [LoadableRelation] public ICollection? Shows { get; set; } + [SerializeIgnore] public ICollection? Shows { get; set; } /// public Dictionary ExternalId { get; set; } = new(); diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs index 0304a475..73927e64 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs @@ -123,17 +123,17 @@ namespace Kyoo.Abstractions.Models /// /// The Studio that made this show. /// - [LoadableRelation(nameof(StudioId))][EditableRelation] public Studio? Studio { get; set; } + [LoadableRelation(nameof(StudioId))] public Studio? Studio { get; set; } /// /// The list of people that made this show. /// - [LoadableRelation][EditableRelation] public ICollection? People { get; set; } + [SerializeIgnore] public ICollection? People { get; set; } /// /// The list of collections that contains this show. /// - [LoadableRelation] public ICollection? Collections { get; set; } + [SerializeIgnore] public ICollection? Collections { get; set; } /// /// Links to watch this movie. diff --git a/back/src/Kyoo.Abstractions/Models/Resources/People.cs b/back/src/Kyoo.Abstractions/Models/Resources/People.cs index 0c85c031..052d769c 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/People.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/People.cs @@ -61,7 +61,7 @@ namespace Kyoo.Abstractions.Models /// /// The list of roles this person has played in. See for more information. /// - [EditableRelation][LoadableRelation] public ICollection? Roles { get; set; } + [SerializeIgnore] public ICollection? Roles { get; set; } public People() { } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Season.cs b/back/src/Kyoo.Abstractions/Models/Resources/Season.cs index ae2c199c..dd280c87 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Season.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Season.cs @@ -121,7 +121,7 @@ namespace Kyoo.Abstractions.Models /// /// The list of episodes that this season contains. /// - [LoadableRelation] public ICollection? Episodes { get; set; } + [SerializeIgnore] public ICollection? Episodes { get; set; } /// /// The number of episodes in this season. diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs index 07e8935f..8d8c888c 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs @@ -124,29 +124,29 @@ namespace Kyoo.Abstractions.Models /// /// The Studio that made this show. /// - [LoadableRelation(nameof(StudioId))][EditableRelation] public Studio? Studio { get; set; } + [LoadableRelation(nameof(StudioId))] public Studio? Studio { get; set; } /// /// The list of people that made this show. /// - [LoadableRelation][EditableRelation] public ICollection? People { get; set; } + [SerializeIgnore] public ICollection? People { get; set; } /// /// The different seasons in this show. If this is a movie, this list is always null or empty. /// - [LoadableRelation] public ICollection? Seasons { get; set; } + [SerializeIgnore] public ICollection? Seasons { get; set; } /// /// The list of episodes in this show. /// If this is a movie, there will be a unique episode (with the seasonNumber and episodeNumber set to null). /// Having an episode is necessary to store metadata and tracks. /// - [LoadableRelation] public ICollection? Episodes { get; set; } + [SerializeIgnore] public ICollection? Episodes { get; set; } /// /// The list of collections that contains this show. /// - [LoadableRelation] public ICollection? Collections { get; set; } + [SerializeIgnore] public ICollection? Collections { get; set; } /// /// The first episode of this show. diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs b/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs index a1ab6847..fd09b8af 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs @@ -47,12 +47,12 @@ namespace Kyoo.Abstractions.Models /// /// The list of shows that are made by this studio. /// - [LoadableRelation] public ICollection? Shows { get; set; } + [SerializeIgnore] public ICollection? Shows { get; set; } /// /// The list of movies that are made by this studio. /// - [LoadableRelation] public ICollection? Movies { get; set; } + [SerializeIgnore] public ICollection? Movies { get; set; } /// public Dictionary ExternalId { get; set; } = new(); diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Include.cs b/back/src/Kyoo.Abstractions/Models/Utils/Include.cs index 611922dd..51549c01 100644 --- a/back/src/Kyoo.Abstractions/Models/Utils/Include.cs +++ b/back/src/Kyoo.Abstractions/Models/Utils/Include.cs @@ -17,6 +17,7 @@ // along with Kyoo. If not, see . using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; @@ -59,7 +60,19 @@ public class Include throw new ValidationException($"No loadable relation with the name {key}."); if (attr.RelationID != null) return new SingleRelation(prop.Name, prop.PropertyType, attr.RelationID); - return new MultipleRelation(prop.Name); + + // Multiples relations are disabled due to: + // - Cartesian Explosions perfs + // - Code complexity added. + // if (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType) && prop.PropertyType != typeof(string)) + // { + // // The property is either a list or a an array. + // return new MultipleRelation( + // prop.Name, + // prop.PropertyType.GetElementType() ?? prop.PropertyType.GenericTypeArguments.First() + // ); + // } + throw new NotImplementedException(); }).ToArray() }; } @@ -67,6 +80,4 @@ public class Include public abstract record Metadata(string Name); public record SingleRelation(string Name, Type type, string RelationIdName) : Metadata(Name); - - public record MultipleRelation(string Name) : Metadata(Name); } diff --git a/front/packages/ui/src/details/collection.tsx b/front/packages/ui/src/details/collection.tsx index e05bdc5b..b9463617 100644 --- a/front/packages/ui/src/details/collection.tsx +++ b/front/packages/ui/src/details/collection.tsx @@ -18,10 +18,17 @@ * along with Kyoo. If not, see . */ -import { KyooImage } from "@kyoo/models"; -import { H2, ImageBackground, Link, P, focusReset, ts } from "@kyoo/primitives"; +import { + Collection, + CollectionP, + KyooImage, + QueryIdentifier, + useInfiniteFetch, +} from "@kyoo/models"; +import { Container, H2, ImageBackground, Link, P, focusReset, ts } from "@kyoo/primitives"; import { useTranslation } from "react-i18next"; import { Theme, useYoshiki } from "yoshiki/native"; +import { ErrorView, Fetch } from "../fetch"; export const PartOf = ({ name, @@ -69,3 +76,36 @@ export const PartOf = ({ ); }; + +export const DetailsCollections = ({ type, slug }: { type: "movie" | "show"; slug: string }) => { + const { items, error } = useInfiniteFetch(DetailsCollections.query(type, slug)); + const { css } = useYoshiki(); + + if (error) return ; + + // Since most items dont have collections, not having a skeleton reduces layout shifts. + if (!items) return null; + + return ( + + {items.map((x) => ( + + ))} + + ); +}; + +DetailsCollections.query = (type: "movie" | "show", slug: string): QueryIdentifier => ({ + parser: CollectionP, + path: [type, slug, "collections"], + params: { + limit: 0, + }, + infinite: true, +}); diff --git a/front/packages/ui/src/details/header.tsx b/front/packages/ui/src/details/header.tsx index 555c4a79..26eef47f 100644 --- a/front/packages/ui/src/details/header.tsx +++ b/front/packages/ui/src/details/header.tsx @@ -459,19 +459,6 @@ export const Header = ({ ))} - {data?.collections && ( - - {data.collections.map((x) => ( - - ))} - - )} )} diff --git a/front/packages/ui/src/details/movie.tsx b/front/packages/ui/src/details/movie.tsx index f730ba12..7650911d 100644 --- a/front/packages/ui/src/details/movie.tsx +++ b/front/packages/ui/src/details/movie.tsx @@ -23,12 +23,13 @@ import { Platform, ScrollView } from "react-native"; import { useYoshiki } from "yoshiki/native"; import { DefaultLayout } from "../layout"; import { Header } from "./header"; +import { DetailsCollections } from "./collection"; const query = (slug: string): QueryIdentifier => ({ parser: MovieP, path: ["movies", slug], params: { - fields: ["studio", "collections"], + fields: ["studio"], }, }); @@ -49,6 +50,7 @@ export const MovieDetails: QueryPage<{ slug: string }> = ({ slug }) => { )} >
+ {/* */} ); @@ -56,6 +58,7 @@ export const MovieDetails: QueryPage<{ slug: string }> = ({ slug }) => { MovieDetails.getFetchUrls = ({ slug }) => [ query(slug), + DetailsCollections.query("movie", slug), // ShowStaff.query(slug), ]; diff --git a/front/packages/ui/src/details/show.tsx b/front/packages/ui/src/details/show.tsx index 298d778b..33081315 100644 --- a/front/packages/ui/src/details/show.tsx +++ b/front/packages/ui/src/details/show.tsx @@ -27,6 +27,7 @@ import { Header } from "./header"; import Svg, { Path, SvgProps } from "react-native-svg"; import { Container } from "@kyoo/primitives"; import { forwardRef } from "react"; +import { DetailsCollections } from "./collection"; export const SvgWave = (props: SvgProps) => { const { css } = useYoshiki(); @@ -65,6 +66,7 @@ const ShowHeader = forwardRef(function ShowH )} >
+ {/* */} = ({ slug, ShowDetails.getFetchUrls = ({ slug, season }) => [ query(slug), + DetailsCollections.query("show", slug), // ShowStaff.query(slug), EpisodeList.query(slug, season), SeasonHeader.query(slug),