From 079df8a1c7a209acd207a0a433b2e799f18820ba Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Thu, 28 Jan 2021 22:32:10 +0100 Subject: [PATCH] Adding a IResourceLink interface & fixing most of the editing --- Kyoo.Common/Models/MetadataID.cs | 1 + Kyoo.Common/Models/Resources/IResource.cs | 58 +++++++++++++ Kyoo.Common/Utility.cs | 82 +++++++++++++++--- Kyoo.CommonAPI/LocalRepository.cs | 4 +- .../Repositories/LibraryItemRepository.cs | 4 +- .../Repositories/LibraryRepository.cs | 2 +- .../Repositories/ShowRepository.cs | 8 +- Kyoo/Kyoo.csproj | 3 +- Kyoo/Models/DatabaseContext.cs | 24 +++--- ....cs => 20210128212212_Initial.Designer.cs} | 81 ++++++++---------- ...0_Initial.cs => 20210128212212_Initial.cs} | 83 ++++++++----------- .../Internal/DatabaseContextModelSnapshot.cs | 79 ++++++++---------- Kyoo/Models/Links/CollectionLink.cs | 21 +++-- Kyoo/Models/Links/GenreLink.cs | 16 ++-- Kyoo/Models/Links/ProviderLink.cs | 17 ++-- Kyoo/Models/Resources/CollectionDE.cs | 6 +- Kyoo/Models/Resources/GenreDE.cs | 4 +- Kyoo/Models/Resources/LibraryDE.cs | 4 +- Kyoo/Models/Resources/ShowDE.cs | 8 +- 19 files changed, 294 insertions(+), 211 deletions(-) rename Kyoo/Models/DatabaseMigrations/Internal/{20200816151940_Initial.Designer.cs => 20210128212212_Initial.Designer.cs} (91%) rename Kyoo/Models/DatabaseMigrations/Internal/{20200816151940_Initial.cs => 20210128212212_Initial.cs} (91%) diff --git a/Kyoo.Common/Models/MetadataID.cs b/Kyoo.Common/Models/MetadataID.cs index 945e578b..6ea84afa 100644 --- a/Kyoo.Common/Models/MetadataID.cs +++ b/Kyoo.Common/Models/MetadataID.cs @@ -1,3 +1,4 @@ +using System; using Kyoo.Models.Attributes; namespace Kyoo.Models diff --git a/Kyoo.Common/Models/Resources/IResource.cs b/Kyoo.Common/Models/Resources/IResource.cs index 7ef6c4df..74c8dcf4 100644 --- a/Kyoo.Common/Models/Resources/IResource.cs +++ b/Kyoo.Common/Models/Resources/IResource.cs @@ -1,3 +1,6 @@ +using System; +using System.Collections.Generic; + namespace Kyoo.Models { public interface IResource @@ -5,4 +8,59 @@ namespace Kyoo.Models public int ID { get; set; } public string Slug { get; } } + + public interface IResourceLink + where T : IResource + where T2 : IResource + { + public T Parent { get; } + public int ParentID { get; } + public T2 Child { get; } + public int ChildID { get; } + } + + public class ResourceComparer : IEqualityComparer where T : IResource + { + public bool Equals(T x, T y) + { + if (ReferenceEquals(x, y)) + return true; + if (ReferenceEquals(x, null)) + return false; + if (ReferenceEquals(y, null)) + return false; + if (x.GetType() != y.GetType()) + return false; + return x.ID == y.ID || x.Slug == y.Slug; + } + + public int GetHashCode(T obj) + { + return HashCode.Combine(obj.ID, obj.Slug); + } + } + + public class LinkComparer : IEqualityComparer> + where T : IResource + where T2 : IResource + { + public bool Equals(IResourceLink x, IResourceLink y) + { + if (ReferenceEquals(x, y)) + return true; + if (ReferenceEquals(x, null)) + return false; + if (ReferenceEquals(y, null)) + return false; + if (x.GetType() != y.GetType()) + return false; + return Utility.LinkEquals(x.Parent, x.ParentID, y.Parent, y.ParentID) + && Utility.LinkEquals(x.Child, x.ChildID, y.Child, y.ChildID); + } + + public int GetHashCode(IResourceLink obj) + { + return HashCode.Combine(obj.Parent, obj.ParentID, obj.Child, obj.ChildID); + } + } } \ No newline at end of file diff --git a/Kyoo.Common/Utility.cs b/Kyoo.Common/Utility.cs index 94e69a51..daeaece8 100644 --- a/Kyoo.Common/Utility.cs +++ b/Kyoo.Common/Utility.cs @@ -147,7 +147,7 @@ namespace Kyoo else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && property.PropertyType != typeof(string)) { - property.SetValue(first, RunGenericMethod( + property.SetValue(first, RunGenericMethod( typeof(Utility), "MergeLists", GetEnumerableType(property.PropertyType), @@ -189,18 +189,25 @@ namespace Kyoo { if (obj == null) throw new ArgumentNullException(nameof(obj)); + return IsOfGenericType(obj.GetType(), genericType); + } + + public static bool IsOfGenericType([NotNull] Type type, [NotNull] Type genericType) + { + if (type == null) + throw new ArgumentNullException(nameof(type)); if (genericType == null) throw new ArgumentNullException(nameof(genericType)); if (!genericType.IsGenericType) throw new ArgumentException($"{nameof(genericType)} is not a generic type."); IEnumerable types = genericType.IsInterface - ? obj.GetType().GetInterfaces() - : obj.GetType().GetInheritanceTree(); - return types.Any(type => type.IsGenericType && type.GetGenericTypeDefinition() == genericType); + ? type.GetInterfaces() + : type.GetInheritanceTree(); + return types.Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericType); } - public static object RunGenericMethod( + public static T RunGenericMethod( [NotNull] Type owner, [NotNull] string methodName, [NotNull] Type type, @@ -212,13 +219,14 @@ namespace Kyoo throw new ArgumentNullException(nameof(methodName)); if (type == null) throw new ArgumentNullException(nameof(type)); - MethodInfo method = owner.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + MethodInfo method = owner.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) + .SingleOrDefault(x => x.Name == methodName && x.GetParameters().Length == args.Length); if (method == null) - throw new NullReferenceException($"A method named {methodName} could not be found on {owner.FullName}"); - return method.MakeGenericMethod(type).Invoke(null, args?.ToArray()); + throw new NullReferenceException($"A method named {methodName} with {args.Length} arguments could not be found on {owner.FullName}"); + return (T)method.MakeGenericMethod(type).Invoke(null, args?.ToArray()); } - public static object RunGenericMethod( + public static T RunGenericMethod( [NotNull] object instance, [NotNull] string methodName, [NotNull] Type type, @@ -233,9 +241,10 @@ namespace Kyoo MethodInfo method = instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) throw new NullReferenceException($"A method named {methodName} could not be found on {instance.GetType().FullName}"); - return method.MakeGenericMethod(type).Invoke(instance, args?.ToArray()); + return (T)method.MakeGenericMethod(type).Invoke(instance, args?.ToArray()); } + [NotNull] public static Type GetEnumerableType([NoEnumeration] [NotNull] IEnumerable list) { if (list == null) @@ -334,6 +343,59 @@ namespace Kyoo }, TaskContinuationOptions.ExecuteSynchronously); } + public static bool ResourceEquals([CanBeNull] object first, [CanBeNull] object second) + { + if (ReferenceEquals(first, second)) + return true; + if (first is IResource f && second is IResource s) + return ResourceEquals(f, s); + IEnumerable eno = first as IEnumerable; + IEnumerable ens = second as IEnumerable; + if (eno == null || ens == null) + throw new ArgumentException("Arguments are not resources or lists of resources."); + Type type = GetEnumerableType(eno); + if (typeof(IResource).IsAssignableFrom(type)) + return ResourceEquals(eno.Cast(), ens.Cast()); + // if (IsOfGenericType(type, typeof(IResourceLink<,>))) + // return ResourceEquals(eno.Cast>()) + return RunGenericMethod(typeof(Enumerable), "SequenceEqual", type, first, second); + } + + public static bool ResourceEquals([CanBeNull] T first, [CanBeNull] T second) + where T : IResource + { + if (ReferenceEquals(first, second)) + return true; + if (first == null || second == null) + return false; + return first.ID == second.ID || first.Slug == second.Slug; + } + + public static bool ResourceEquals([CanBeNull] IEnumerable first, [CanBeNull] IEnumerable second) + where T : IResource + { + if (ReferenceEquals(first, second)) + return true; + if (first == null || second == null) + return false; + return first.SequenceEqual(second, new ResourceComparer()); + } + + public static bool LinkEquals([CanBeNull] T first, int? firstID, [CanBeNull] T second, int? secondID) + where T : IResource + { + if (ResourceEquals(first, second)) + return true; + if (first == null && second != null + && firstID == second.ID) + return true; + if (first != null && second == null + && first.ID == secondID) + return true; + return firstID == secondID; + + } + public static Expression Convert([CanBeNull] this Expression expr) where T : Delegate { diff --git a/Kyoo.CommonAPI/LocalRepository.cs b/Kyoo.CommonAPI/LocalRepository.cs index 4927da83..add826bf 100644 --- a/Kyoo.CommonAPI/LocalRepository.cs +++ b/Kyoo.CommonAPI/LocalRepository.cs @@ -175,7 +175,7 @@ namespace Kyoo.Controllers if (getter.HasDefaultValue(edited)) continue; await navigation.LoadAsync(); - if (getter.GetClrValue(edited) != getter.GetClrValue(old)) + if (Utility.ResourceEquals(getter.GetClrValue(edited), getter.GetClrValue(old))) { navigation.Metadata.PropertyInfo.SetValue(edited, default); Console.WriteLine($"Loaded: {navigation.Metadata.Name}"); @@ -237,7 +237,7 @@ namespace Kyoo.Controllers object value = property.GetValue(resource); if (value == null || value is ICollection || Utility.IsOfGenericType(value, typeof(ICollection<>))) continue; - value = Utility.RunGenericMethod(typeof(Enumerable), "ToList", Utility.GetEnumerableType((IEnumerable)value), value); + value = Utility.RunGenericMethod(typeof(Enumerable), "ToList", Utility.GetEnumerableType((IEnumerable)value), value); property.SetValue(resource, value); } return Task.CompletedTask; diff --git a/Kyoo/Controllers/Repositories/LibraryItemRepository.cs b/Kyoo/Controllers/Repositories/LibraryItemRepository.cs index ff45d342..b8c5cc17 100644 --- a/Kyoo/Controllers/Repositories/LibraryItemRepository.cs +++ b/Kyoo/Controllers/Repositories/LibraryItemRepository.cs @@ -71,7 +71,7 @@ namespace Kyoo.Controllers private IQueryable ItemsQuery => _database.Shows - .Where(x => !_database.CollectionLinks.Any(y => y.ShowID == x.ID)) + .Where(x => !_database.CollectionLinks.Any(y => y.ChildID == x.ID)) .Select(LibraryItem.FromShow) .Concat(_database.Collections .Select(LibraryItem.FromCollection)); @@ -118,7 +118,7 @@ namespace Kyoo.Controllers .Where(selector) .Select(x => x.Show) .Where(x => x != null) - .Where(x => !_database.CollectionLinks.Any(y => y.ShowID == x.ID)) + .Where(x => !_database.CollectionLinks.Any(y => y.ChildID == x.ID)) .Select(LibraryItem.FromShow) .Concat(_database.LibraryLinks .Where(selector) diff --git a/Kyoo/Controllers/Repositories/LibraryRepository.cs b/Kyoo/Controllers/Repositories/LibraryRepository.cs index 123285e6..86cdee90 100644 --- a/Kyoo/Controllers/Repositories/LibraryRepository.cs +++ b/Kyoo/Controllers/Repositories/LibraryRepository.cs @@ -77,7 +77,7 @@ namespace Kyoo.Controllers if (resource.ProviderLinks != null) foreach (ProviderLink link in resource.ProviderLinks) if (ShouldValidate(link)) - link.Provider = await _providers.CreateIfNotExists(link.Provider, true); + link.Child = await _providers.CreateIfNotExists(link.Child, true); } public override async Task Delete(LibraryDE obj) diff --git a/Kyoo/Controllers/Repositories/ShowRepository.cs b/Kyoo/Controllers/Repositories/ShowRepository.cs index ba0cfed2..f1f0fef4 100644 --- a/Kyoo/Controllers/Repositories/ShowRepository.cs +++ b/Kyoo/Controllers/Repositories/ShowRepository.cs @@ -90,8 +90,8 @@ namespace Kyoo.Controllers { foreach (GenreLink entry in obj.GenreLinks) { - if (!(entry.Genre is GenreDE)) - entry.Genre = new GenreDE(entry.Genre); + if (!(entry.Child is GenreDE)) + entry.Child = new GenreDE(entry.Child); _database.Entry(entry).State = EntityState.Added; } } @@ -117,7 +117,7 @@ namespace Kyoo.Controllers if (resource.GenreLinks != null) foreach (GenreLink link in resource.GenreLinks) if (ShouldValidate(link)) - link.Genre = await _genres.CreateIfNotExists(link.Genre, true); + link.Child = await _genres.CreateIfNotExists(link.Child, true); if (resource.People != null) foreach (PeopleRole link in resource.People) @@ -134,7 +134,7 @@ namespace Kyoo.Controllers { if (collectionID != null) { - await _database.CollectionLinks.AddAsync(new CollectionLink {CollectionID = collectionID, ShowID = showID}); + await _database.CollectionLinks.AddAsync(new CollectionLink {ParentID = collectionID.Value, ChildID = showID}); await _database.SaveIfNoDuplicates(); } if (libraryID != null) diff --git a/Kyoo/Kyoo.csproj b/Kyoo/Kyoo.csproj index 68eb1989..5ab21e23 100644 --- a/Kyoo/Kyoo.csproj +++ b/Kyoo/Kyoo.csproj @@ -104,6 +104,7 @@ - + + diff --git a/Kyoo/Models/DatabaseContext.cs b/Kyoo/Models/DatabaseContext.cs index f97c4f7f..4730cea2 100644 --- a/Kyoo/Models/DatabaseContext.cs +++ b/Kyoo/Models/DatabaseContext.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; using Kyoo.Models; using Kyoo.Models.Exceptions; -using Kyoo.Models.Watch; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Npgsql; @@ -78,8 +77,16 @@ namespace Kyoo .Property(t => t.IsForced) .ValueGeneratedNever(); + modelBuilder.Entity() - .HasKey(x => new {x.ShowID, x.GenreID}); + .HasKey(x => new {ShowID = x.ParentID, GenreID = x.ChildID}); + + modelBuilder.Entity() + .HasKey(x => new {CollectionID = x.ParentID, ShowID = x.ChildID}); + + modelBuilder.Entity() + .HasKey(x => new {LibraryID = x.ParentID, ProviderID = x.ChildID}); + modelBuilder.Entity() .Ignore(x => x.Shows) @@ -119,25 +126,25 @@ namespace Kyoo .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() - .HasOne(x => x.Collection as CollectionDE) + .HasOne(x => x.Parent as CollectionDE) .WithMany(x => x.Links) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() - .HasOne(x => x.Show as ShowDE) + .HasOne(x => x.Child as ShowDE) .WithMany(x => x.CollectionLinks) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() - .HasOne(x => x.Genre as GenreDE) + .HasOne(x => x.Child as GenreDE) .WithMany(x => x.Links) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() - .HasOne(x => x.Show as ShowDE) + .HasOne(x => x.Parent as ShowDE) .WithMany(x => x.GenreLinks) .OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity() - .HasOne(x => x.Library as LibraryDE) + .HasOne(x => x.Parent as LibraryDE) .WithMany(x => x.ProviderLinks) .OnDelete(DeleteBehavior.Cascade); @@ -211,9 +218,6 @@ namespace Kyoo modelBuilder.Entity() .HasIndex(x => new {x.LibraryID, x.CollectionID}) .IsUnique(); - modelBuilder.Entity() - .HasIndex(x => new {x.CollectionID, x.ShowID}) - .IsUnique(); } public override int SaveChanges() diff --git a/Kyoo/Models/DatabaseMigrations/Internal/20200816151940_Initial.Designer.cs b/Kyoo/Models/DatabaseMigrations/Internal/20210128212212_Initial.Designer.cs similarity index 91% rename from Kyoo/Models/DatabaseMigrations/Internal/20200816151940_Initial.Designer.cs rename to Kyoo/Models/DatabaseMigrations/Internal/20210128212212_Initial.Designer.cs index 706375cc..e9e02cef 100644 --- a/Kyoo/Models/DatabaseMigrations/Internal/20200816151940_Initial.Designer.cs +++ b/Kyoo/Models/DatabaseMigrations/Internal/20210128212212_Initial.Designer.cs @@ -11,7 +11,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace Kyoo.Models.DatabaseMigrations.Internal { [DbContext(typeof(DatabaseContext))] - [Migration("20200816151940_Initial")] + [Migration("20210128212212_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -20,7 +20,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder .HasAnnotation("Npgsql:Enum:item_type", "show,movie,collection") .HasAnnotation("Npgsql:Enum:status", "finished,airing,planned,unknown") - .HasAnnotation("Npgsql:Enum:stream_type", "unknow,video,audio,subtitle") + .HasAnnotation("Npgsql:Enum:stream_type", "unknown,video,audio,subtitle,font") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) .HasAnnotation("ProductVersion", "3.1.3") .HasAnnotation("Relational:MaxIdentifierLength", 63); @@ -57,23 +57,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.CollectionLink", b => { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("CollectionID") + b.Property("ParentID") .HasColumnType("integer"); - b.Property("ShowID") + b.Property("ChildID") .HasColumnType("integer"); - b.HasKey("ID"); + b.HasKey("ParentID", "ChildID"); - b.HasIndex("ShowID"); - - b.HasIndex("CollectionID", "ShowID") - .IsUnique(); + b.HasIndex("ChildID"); b.ToTable("CollectionLinks"); }); @@ -154,15 +146,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.GenreLink", b => { - b.Property("ShowID") + b.Property("ParentID") .HasColumnType("integer"); - b.Property("GenreID") + b.Property("ChildID") .HasColumnType("integer"); - b.HasKey("ShowID", "GenreID"); + b.HasKey("ParentID", "ChildID"); - b.HasIndex("GenreID"); + b.HasIndex("ChildID"); b.ToTable("GenreLinks"); }); @@ -348,22 +340,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.ProviderLink", b => { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("LibraryID") + b.Property("ParentID") .HasColumnType("integer"); - b.Property("ProviderID") + b.Property("ChildID") .HasColumnType("integer"); - b.HasKey("ID"); + b.HasKey("ParentID", "ChildID"); - b.HasIndex("LibraryID"); - - b.HasIndex("ProviderID"); + b.HasIndex("ChildID"); b.ToTable("ProviderLinks"); }); @@ -528,14 +513,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.CollectionLink", b => { - b.HasOne("Kyoo.Models.CollectionDE", "Collection") - .WithMany("Links") - .HasForeignKey("CollectionID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.ShowDE", "Show") + b.HasOne("Kyoo.Models.ShowDE", "Child") .WithMany("CollectionLinks") - .HasForeignKey("ShowID") + .HasForeignKey("ChildID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Kyoo.Models.CollectionDE", "Parent") + .WithMany("Links") + .HasForeignKey("ParentID") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); @@ -555,15 +541,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.GenreLink", b => { - b.HasOne("Kyoo.Models.GenreDE", "Genre") + b.HasOne("Kyoo.Models.GenreDE", "Child") .WithMany("Links") - .HasForeignKey("GenreID") + .HasForeignKey("ChildID") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Kyoo.Models.ShowDE", "Show") + b.HasOne("Kyoo.Models.ShowDE", "Parent") .WithMany("GenreLinks") - .HasForeignKey("ShowID") + .HasForeignKey("ParentID") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); @@ -633,14 +619,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.ProviderLink", b => { - b.HasOne("Kyoo.Models.LibraryDE", "Library") - .WithMany("ProviderLinks") - .HasForeignKey("LibraryID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.ProviderID", "Provider") + b.HasOne("Kyoo.Models.ProviderID", "Child") .WithMany() - .HasForeignKey("ProviderID") + .HasForeignKey("ChildID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Kyoo.Models.LibraryDE", "Parent") + .WithMany("ProviderLinks") + .HasForeignKey("ParentID") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); diff --git a/Kyoo/Models/DatabaseMigrations/Internal/20200816151940_Initial.cs b/Kyoo/Models/DatabaseMigrations/Internal/20210128212212_Initial.cs similarity index 91% rename from Kyoo/Models/DatabaseMigrations/Internal/20200816151940_Initial.cs rename to Kyoo/Models/DatabaseMigrations/Internal/20210128212212_Initial.cs index d6243aca..04349e48 100644 --- a/Kyoo/Models/DatabaseMigrations/Internal/20200816151940_Initial.cs +++ b/Kyoo/Models/DatabaseMigrations/Internal/20210128212212_Initial.cs @@ -11,7 +11,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal migrationBuilder.AlterDatabase() .Annotation("Npgsql:Enum:item_type", "show,movie,collection") .Annotation("Npgsql:Enum:status", "finished,airing,planned,unknown") - .Annotation("Npgsql:Enum:stream_type", "unknow,video,audio,subtitle"); + .Annotation("Npgsql:Enum:stream_type", "unknown,video,audio,subtitle,font"); migrationBuilder.CreateTable( name: "Collections", @@ -106,24 +106,22 @@ namespace Kyoo.Models.DatabaseMigrations.Internal name: "ProviderLinks", columns: table => new { - ID = table.Column(nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - ProviderID = table.Column(nullable: false), - LibraryID = table.Column(nullable: true) + ParentID = table.Column(nullable: false), + ChildID = table.Column(nullable: false) }, constraints: table => { - table.PrimaryKey("PK_ProviderLinks", x => x.ID); + table.PrimaryKey("PK_ProviderLinks", x => new { x.ParentID, x.ChildID }); table.ForeignKey( - name: "FK_ProviderLinks_Libraries_LibraryID", - column: x => x.LibraryID, - principalTable: "Libraries", + name: "FK_ProviderLinks_Providers_ChildID", + column: x => x.ChildID, + principalTable: "Providers", principalColumn: "ID", onDelete: ReferentialAction.Cascade); table.ForeignKey( - name: "FK_ProviderLinks_Providers_ProviderID", - column: x => x.ProviderID, - principalTable: "Providers", + name: "FK_ProviderLinks_Libraries_ParentID", + column: x => x.ParentID, + principalTable: "Libraries", principalColumn: "ID", onDelete: ReferentialAction.Cascade); }); @@ -164,24 +162,22 @@ namespace Kyoo.Models.DatabaseMigrations.Internal name: "CollectionLinks", columns: table => new { - ID = table.Column(nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - CollectionID = table.Column(nullable: true), - ShowID = table.Column(nullable: false) + ParentID = table.Column(nullable: false), + ChildID = table.Column(nullable: false) }, constraints: table => { - table.PrimaryKey("PK_CollectionLinks", x => x.ID); + table.PrimaryKey("PK_CollectionLinks", x => new { x.ParentID, x.ChildID }); table.ForeignKey( - name: "FK_CollectionLinks_Collections_CollectionID", - column: x => x.CollectionID, - principalTable: "Collections", + name: "FK_CollectionLinks_Shows_ChildID", + column: x => x.ChildID, + principalTable: "Shows", principalColumn: "ID", onDelete: ReferentialAction.Cascade); table.ForeignKey( - name: "FK_CollectionLinks_Shows_ShowID", - column: x => x.ShowID, - principalTable: "Shows", + name: "FK_CollectionLinks_Collections_ParentID", + column: x => x.ParentID, + principalTable: "Collections", principalColumn: "ID", onDelete: ReferentialAction.Cascade); }); @@ -190,21 +186,21 @@ namespace Kyoo.Models.DatabaseMigrations.Internal name: "GenreLinks", columns: table => new { - ShowID = table.Column(nullable: false), - GenreID = table.Column(nullable: false) + ParentID = table.Column(nullable: false), + ChildID = table.Column(nullable: false) }, constraints: table => { - table.PrimaryKey("PK_GenreLinks", x => new { x.ShowID, x.GenreID }); + table.PrimaryKey("PK_GenreLinks", x => new { x.ParentID, x.ChildID }); table.ForeignKey( - name: "FK_GenreLinks_Genres_GenreID", - column: x => x.GenreID, + name: "FK_GenreLinks_Genres_ChildID", + column: x => x.ChildID, principalTable: "Genres", principalColumn: "ID", onDelete: ReferentialAction.Cascade); table.ForeignKey( - name: "FK_GenreLinks_Shows_ShowID", - column: x => x.ShowID, + name: "FK_GenreLinks_Shows_ParentID", + column: x => x.ParentID, principalTable: "Shows", principalColumn: "ID", onDelete: ReferentialAction.Cascade); @@ -407,15 +403,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal }); migrationBuilder.CreateIndex( - name: "IX_CollectionLinks_ShowID", + name: "IX_CollectionLinks_ChildID", table: "CollectionLinks", - column: "ShowID"); - - migrationBuilder.CreateIndex( - name: "IX_CollectionLinks_CollectionID_ShowID", - table: "CollectionLinks", - columns: new[] { "CollectionID", "ShowID" }, - unique: true); + column: "ChildID"); migrationBuilder.CreateIndex( name: "IX_Collections_Slug", @@ -435,9 +425,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal unique: true); migrationBuilder.CreateIndex( - name: "IX_GenreLinks_GenreID", + name: "IX_GenreLinks_ChildID", table: "GenreLinks", - column: "GenreID"); + column: "ChildID"); migrationBuilder.CreateIndex( name: "IX_Genres_Slug", @@ -515,14 +505,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal column: "ShowID"); migrationBuilder.CreateIndex( - name: "IX_ProviderLinks_LibraryID", + name: "IX_ProviderLinks_ChildID", table: "ProviderLinks", - column: "LibraryID"); - - migrationBuilder.CreateIndex( - name: "IX_ProviderLinks_ProviderID", - table: "ProviderLinks", - column: "ProviderID"); + column: "ChildID"); migrationBuilder.CreateIndex( name: "IX_Providers_Slug", @@ -592,10 +577,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal name: "People"); migrationBuilder.DropTable( - name: "Libraries"); + name: "Providers"); migrationBuilder.DropTable( - name: "Providers"); + name: "Libraries"); migrationBuilder.DropTable( name: "Episodes"); diff --git a/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs b/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs index 5e3bd4b4..ac3e38f6 100644 --- a/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs +++ b/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs @@ -18,7 +18,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder .HasAnnotation("Npgsql:Enum:item_type", "show,movie,collection") .HasAnnotation("Npgsql:Enum:status", "finished,airing,planned,unknown") - .HasAnnotation("Npgsql:Enum:stream_type", "unknow,video,audio,subtitle") + .HasAnnotation("Npgsql:Enum:stream_type", "unknown,video,audio,subtitle,font") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) .HasAnnotation("ProductVersion", "3.1.3") .HasAnnotation("Relational:MaxIdentifierLength", 63); @@ -55,23 +55,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.CollectionLink", b => { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("CollectionID") + b.Property("ParentID") .HasColumnType("integer"); - b.Property("ShowID") + b.Property("ChildID") .HasColumnType("integer"); - b.HasKey("ID"); + b.HasKey("ParentID", "ChildID"); - b.HasIndex("ShowID"); - - b.HasIndex("CollectionID", "ShowID") - .IsUnique(); + b.HasIndex("ChildID"); b.ToTable("CollectionLinks"); }); @@ -152,15 +144,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.GenreLink", b => { - b.Property("ShowID") + b.Property("ParentID") .HasColumnType("integer"); - b.Property("GenreID") + b.Property("ChildID") .HasColumnType("integer"); - b.HasKey("ShowID", "GenreID"); + b.HasKey("ParentID", "ChildID"); - b.HasIndex("GenreID"); + b.HasIndex("ChildID"); b.ToTable("GenreLinks"); }); @@ -346,22 +338,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.ProviderLink", b => { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("LibraryID") + b.Property("ParentID") .HasColumnType("integer"); - b.Property("ProviderID") + b.Property("ChildID") .HasColumnType("integer"); - b.HasKey("ID"); + b.HasKey("ParentID", "ChildID"); - b.HasIndex("LibraryID"); - - b.HasIndex("ProviderID"); + b.HasIndex("ChildID"); b.ToTable("ProviderLinks"); }); @@ -526,14 +511,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.CollectionLink", b => { - b.HasOne("Kyoo.Models.CollectionDE", "Collection") - .WithMany("Links") - .HasForeignKey("CollectionID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.ShowDE", "Show") + b.HasOne("Kyoo.Models.ShowDE", "Child") .WithMany("CollectionLinks") - .HasForeignKey("ShowID") + .HasForeignKey("ChildID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Kyoo.Models.CollectionDE", "Parent") + .WithMany("Links") + .HasForeignKey("ParentID") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); @@ -553,15 +539,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.GenreLink", b => { - b.HasOne("Kyoo.Models.GenreDE", "Genre") + b.HasOne("Kyoo.Models.GenreDE", "Child") .WithMany("Links") - .HasForeignKey("GenreID") + .HasForeignKey("ChildID") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Kyoo.Models.ShowDE", "Show") + b.HasOne("Kyoo.Models.ShowDE", "Parent") .WithMany("GenreLinks") - .HasForeignKey("ShowID") + .HasForeignKey("ParentID") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); @@ -631,14 +617,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal modelBuilder.Entity("Kyoo.Models.ProviderLink", b => { - b.HasOne("Kyoo.Models.LibraryDE", "Library") - .WithMany("ProviderLinks") - .HasForeignKey("LibraryID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.ProviderID", "Provider") + b.HasOne("Kyoo.Models.ProviderID", "Child") .WithMany() - .HasForeignKey("ProviderID") + .HasForeignKey("ChildID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Kyoo.Models.LibraryDE", "Parent") + .WithMany("ProviderLinks") + .HasForeignKey("ParentID") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); diff --git a/Kyoo/Models/Links/CollectionLink.cs b/Kyoo/Models/Links/CollectionLink.cs index cc8aa040..9af6d1df 100644 --- a/Kyoo/Models/Links/CollectionLink.cs +++ b/Kyoo/Models/Links/CollectionLink.cs @@ -1,21 +1,20 @@ namespace Kyoo.Models { - public class CollectionLink + public class CollectionLink : IResourceLink { - public int ID { get; set; } - public int? CollectionID { get; set; } - public virtual Collection Collection { get; set; } - public int ShowID { get; set; } - public virtual Show Show { get; set; } + public int ParentID { get; set; } + public virtual Collection Parent { get; set; } + public int ChildID { get; set; } + public virtual Show Child { get; set; } public CollectionLink() { } - public CollectionLink(Collection collection, Show show) + public CollectionLink(Collection parent, Show child) { - Collection = collection; - CollectionID = collection.ID; - Show = show; - ShowID = show.ID; + Parent = parent; + ParentID = parent.ID; + Child = child; + ChildID = child.ID; } } } \ No newline at end of file diff --git a/Kyoo/Models/Links/GenreLink.cs b/Kyoo/Models/Links/GenreLink.cs index dce3e1bb..09dbde70 100644 --- a/Kyoo/Models/Links/GenreLink.cs +++ b/Kyoo/Models/Links/GenreLink.cs @@ -1,18 +1,18 @@ namespace Kyoo.Models { - public class GenreLink + public class GenreLink : IResourceLink { - public int ShowID { get; set; } - public virtual Show Show { get; set; } - public int GenreID { get; set; } - public virtual Genre Genre { get; set; } + public int ParentID { get; set; } + public virtual Show Parent { get; set; } + public int ChildID { get; set; } + public virtual Genre Child { get; set; } public GenreLink() {} - public GenreLink(Show show, Genre genre) + public GenreLink(Show parent, Genre child) { - Show = show; - Genre = genre; + Parent = parent; + Child = child; } } } \ No newline at end of file diff --git a/Kyoo/Models/Links/ProviderLink.cs b/Kyoo/Models/Links/ProviderLink.cs index 6bc50b1a..584af900 100644 --- a/Kyoo/Models/Links/ProviderLink.cs +++ b/Kyoo/Models/Links/ProviderLink.cs @@ -2,20 +2,19 @@ using Newtonsoft.Json; namespace Kyoo.Models { - public class ProviderLink + public class ProviderLink : IResourceLink { - [JsonIgnore] public int ID { get; set; } - [JsonIgnore] public int ProviderID { get; set; } - [JsonIgnore] public virtual ProviderID Provider { get; set; } - [JsonIgnore] public int? LibraryID { get; set; } - [JsonIgnore] public virtual Library Library { get; set; } + [JsonIgnore] public int ParentID { get; set; } + [JsonIgnore] public virtual Library Parent { get; set; } + [JsonIgnore] public int ChildID { get; set; } + [JsonIgnore] public virtual ProviderID Child { get; set; } public ProviderLink() { } - public ProviderLink(ProviderID provider, Library library) + public ProviderLink(ProviderID child, Library parent) { - Provider = provider; - Library = library; + Child = child; + Parent = parent; } } } \ No newline at end of file diff --git a/Kyoo/Models/Resources/CollectionDE.cs b/Kyoo/Models/Resources/CollectionDE.cs index 3f330c26..ddc02b55 100644 --- a/Kyoo/Models/Resources/CollectionDE.cs +++ b/Kyoo/Models/Resources/CollectionDE.cs @@ -7,16 +7,16 @@ namespace Kyoo.Models public class CollectionDE : Collection { [JsonIgnore] [NotMergable] public virtual ICollection Links { get; set; } - [ExpressionRewrite(nameof(Links), nameof(CollectionLink.Show))] + [ExpressionRewrite(nameof(Links), nameof(CollectionLink.Child))] public override IEnumerable Shows { - get => Links?.Select(x => x.Show); + get => Links?.Select(x => x.Child); set => Links = value?.Select(x => new CollectionLink(this, x)).ToList(); } [JsonIgnore] [NotMergable] public virtual ICollection LibraryLinks { get; set; } - [ExpressionRewrite(nameof(LibraryLinks), nameof(GenreLink.Genre))] + [ExpressionRewrite(nameof(LibraryLinks), nameof(GenreLink.Child))] public override IEnumerable Libraries { get => LibraryLinks?.Select(x => x.Library); diff --git a/Kyoo/Models/Resources/GenreDE.cs b/Kyoo/Models/Resources/GenreDE.cs index fa44e3b5..1832cd38 100644 --- a/Kyoo/Models/Resources/GenreDE.cs +++ b/Kyoo/Models/Resources/GenreDE.cs @@ -8,10 +8,10 @@ namespace Kyoo.Models { [JsonIgnore] [NotMergable] public virtual ICollection Links { get; set; } - [ExpressionRewrite(nameof(Links), nameof(GenreLink.Genre))] + [ExpressionRewrite(nameof(Links), nameof(GenreLink.Child))] [JsonIgnore] [NotMergable] public override IEnumerable Shows { - get => Links?.Select(x => x.Show); + get => Links?.Select(x => x.Parent); set => Links = value?.Select(x => new GenreLink(x, this)).ToList(); } diff --git a/Kyoo/Models/Resources/LibraryDE.cs b/Kyoo/Models/Resources/LibraryDE.cs index 07febaa6..1bd097bf 100644 --- a/Kyoo/Models/Resources/LibraryDE.cs +++ b/Kyoo/Models/Resources/LibraryDE.cs @@ -7,10 +7,10 @@ namespace Kyoo.Models public class LibraryDE : Library { [EditableRelation] [JsonIgnore] [NotMergable] public virtual ICollection ProviderLinks { get; set; } - [ExpressionRewrite(nameof(ProviderLinks), nameof(ProviderLink.Provider))] + [ExpressionRewrite(nameof(ProviderLinks), nameof(ProviderLink.Child))] public override IEnumerable Providers { - get => ProviderLinks?.Select(x => x.Provider); + get => ProviderLinks?.Select(x => x.Child); set => ProviderLinks = value?.Select(x => new ProviderLink(x, this)).ToList(); } diff --git a/Kyoo/Models/Resources/ShowDE.cs b/Kyoo/Models/Resources/ShowDE.cs index e1ad4d34..04e26994 100644 --- a/Kyoo/Models/Resources/ShowDE.cs +++ b/Kyoo/Models/Resources/ShowDE.cs @@ -7,10 +7,10 @@ namespace Kyoo.Models public class ShowDE : Show { [EditableRelation] [JsonReadOnly] [NotMergable] public virtual ICollection GenreLinks { get; set; } - [ExpressionRewrite(nameof(GenreLinks), nameof(GenreLink.Genre))] + [ExpressionRewrite(nameof(GenreLinks), nameof(GenreLink.Child))] public override IEnumerable Genres { - get => GenreLinks?.Select(x => x.Genre); + get => GenreLinks?.Select(x => x.Child); set => GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList(); } @@ -23,10 +23,10 @@ namespace Kyoo.Models } [JsonReadOnly] [NotMergable] public virtual ICollection CollectionLinks { get; set; } - [ExpressionRewrite(nameof(CollectionLinks), nameof(CollectionLink.Collection))] + [ExpressionRewrite(nameof(CollectionLinks), nameof(CollectionLink.Parent))] public override IEnumerable Collections { - get => CollectionLinks?.Select(x => x.Collection); + get => CollectionLinks?.Select(x => x.Parent); set => CollectionLinks = value?.Select(x => new CollectionLink(x, this)).ToList(); }