// 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 System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; using Kyoo.Abstractions.Models.Attributes; namespace Kyoo.Abstractions.Models.Utils; public class Include { /// /// The aditional fields to include in the result. /// public ICollection Metadatas { get; set; } = ArraySegment.Empty; public abstract record Metadata(string Name); public record SingleRelation(string Name, Type type, string RelationIdName) : Metadata(Name); public record CustomRelation(string Name, Type type, string Sql, string? On, Type Declaring) : Metadata(Name); public record ProjectedRelation(string Name, string Sql) : Metadata(Name); } /// /// The aditional fields to include in the result. /// /// The type related to the new fields public class Include : Include { /// /// The aditional fields names to include in the result. /// public ICollection Fields => Metadatas.Select(x => x.Name).ToList(); public Include() { } public Include(params string[] fields) { Type[] types = typeof(T).GetCustomAttribute()?.Types ?? new[] { typeof(T) }; Metadatas = fields .SelectMany(key => { var relations = types .Select(x => x.GetProperty( key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance )! ) .Select(prop => (prop, attr: prop?.GetCustomAttribute()!) ) .Where(x => x.prop != null && x.attr != null) .ToList(); if (!relations.Any()) throw new ValidationException($"No loadable relation with the name {key}."); return relations .Select(x => { (PropertyInfo prop, LoadableRelationAttribute attr) = x; if (attr.RelationID != null) return new SingleRelation(prop.Name, prop.PropertyType, attr.RelationID) as Metadata; if (attr.Sql != null) return new CustomRelation( prop.Name, prop.PropertyType, attr.Sql, attr.On, prop.DeclaringType! ); if (attr.Projected != null) return new ProjectedRelation(prop.Name, attr.Projected); throw new NotImplementedException(); }) .Distinct(); }) .ToArray(); } public static Include From(string? fields) { if (string.IsNullOrEmpty(fields)) return new Include(); return new Include(fields.Split(',')); } }