2024-02-03 14:55:18 +01:00

110 lines
3.2 KiB
C#

// 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 <https://www.gnu.org/licenses/>.
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
{
/// <summary>
/// The aditional fields to include in the result.
/// </summary>
public ICollection<Metadata> Metadatas { get; set; } = ArraySegment<Metadata>.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);
}
/// <summary>
/// The aditional fields to include in the result.
/// </summary>
/// <typeparam name="T">The type related to the new fields</typeparam>
public class Include<T> : Include
{
/// <summary>
/// The aditional fields names to include in the result.
/// </summary>
public ICollection<string> Fields => Metadatas.Select(x => x.Name).ToList();
public Include() { }
public Include(params string[] fields)
{
Type[] types = typeof(T).GetCustomAttribute<OneOfAttribute>()?.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<LoadableRelationAttribute>()!)
)
.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<T> From(string? fields)
{
if (string.IsNullOrEmpty(fields))
return new Include<T>();
return new Include<T>(fields.Split(','));
}
}