Prepared Seperation of Database components for future multi provider support

This commit is contained in:
JPVenson
2025-01-26 20:45:28 +00:00
parent b318f33599
commit aa811eb1e3
220 changed files with 742 additions and 320 deletions
@@ -0,0 +1,17 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// FluentAPI configuration for the ActivityLog entity.
/// </summary>
public class ActivityLogConfiguration : IEntityTypeConfiguration<ActivityLog>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<ActivityLog> builder)
{
builder.HasIndex(entity => entity.DateCreated);
}
}
@@ -0,0 +1,21 @@
using System;
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// AncestorId configuration.
/// </summary>
public class AncestorIdConfiguration : IEntityTypeConfiguration<AncestorId>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<AncestorId> builder)
{
builder.HasKey(e => new { e.ItemId, e.ParentItemId });
builder.HasIndex(e => e.ParentItemId);
builder.HasOne(e => e.ParentItem).WithMany(e => e.ParentAncestors).HasForeignKey(f => f.ParentItemId);
builder.HasOne(e => e.Item).WithMany(e => e.Children).HasForeignKey(f => f.ItemId);
}
}
@@ -0,0 +1,20 @@
using Jellyfin.Data.Entities.Security;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration
{
/// <summary>
/// FluentAPI configuration for the ApiKey entity.
/// </summary>
public class ApiKeyConfiguration : IEntityTypeConfiguration<ApiKey>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<ApiKey> builder)
{
builder
.HasIndex(entity => entity.AccessToken)
.IsUnique();
}
}
}
@@ -0,0 +1,17 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// FluentAPI configuration for the AttachmentStreamInfo entity.
/// </summary>
public class AttachmentStreamInfoConfiguration : IEntityTypeConfiguration<AttachmentStreamInfo>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<AttachmentStreamInfo> builder)
{
builder.HasKey(e => new { e.ItemId, e.Index });
}
}
@@ -0,0 +1,57 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// Configuration for BaseItem.
/// </summary>
public class BaseItemConfiguration : IEntityTypeConfiguration<BaseItemEntity>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<BaseItemEntity> builder)
{
builder.HasKey(e => e.Id);
// TODO: See rant in entity file.
// builder.HasOne(e => e.Parent).WithMany(e => e.DirectChildren).HasForeignKey(e => e.ParentId);
// builder.HasOne(e => e.TopParent).WithMany(e => e.AllChildren).HasForeignKey(e => e.TopParentId);
// builder.HasOne(e => e.Season).WithMany(e => e.SeasonEpisodes).HasForeignKey(e => e.SeasonId);
// builder.HasOne(e => e.Series).WithMany(e => e.SeriesEpisodes).HasForeignKey(e => e.SeriesId);
builder.HasMany(e => e.Peoples);
builder.HasMany(e => e.UserData);
builder.HasMany(e => e.ItemValues);
builder.HasMany(e => e.MediaStreams);
builder.HasMany(e => e.Chapters);
builder.HasMany(e => e.Provider);
builder.HasMany(e => e.ParentAncestors);
builder.HasMany(e => e.Children);
builder.HasMany(e => e.LockedFields);
builder.HasMany(e => e.TrailerTypes);
builder.HasMany(e => e.Images);
builder.HasIndex(e => e.Path);
builder.HasIndex(e => e.ParentId);
builder.HasIndex(e => e.PresentationUniqueKey);
builder.HasIndex(e => new { e.Id, e.Type, e.IsFolder, e.IsVirtualItem });
// covering index
builder.HasIndex(e => new { e.TopParentId, e.Id });
// series
builder.HasIndex(e => new { e.Type, e.SeriesPresentationUniqueKey, e.PresentationUniqueKey, e.SortName });
// series counts
// seriesdateplayed sort order
builder.HasIndex(e => new { e.Type, e.SeriesPresentationUniqueKey, e.IsFolder, e.IsVirtualItem });
// live tv programs
builder.HasIndex(e => new { e.Type, e.TopParentId, e.StartDate });
// covering index for getitemvalues
builder.HasIndex(e => new { e.Type, e.TopParentId, e.Id });
// used by movie suggestions
builder.HasIndex(e => new { e.Type, e.TopParentId, e.PresentationUniqueKey });
// latest items
builder.HasIndex(e => new { e.Type, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey, e.DateCreated });
builder.HasIndex(e => new { e.IsFolder, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey, e.DateCreated });
// resume
builder.HasIndex(e => new { e.MediaType, e.TopParentId, e.IsVirtualItem, e.PresentationUniqueKey });
}
}
@@ -0,0 +1,18 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// Provides configuration for the BaseItemMetadataField entity.
/// </summary>
public class BaseItemMetadataFieldConfiguration : IEntityTypeConfiguration<BaseItemMetadataField>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<BaseItemMetadataField> builder)
{
builder.HasKey(e => new { e.Id, e.ItemId });
builder.HasOne(e => e.Item);
}
}
@@ -0,0 +1,20 @@
using System;
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// BaseItemProvider configuration.
/// </summary>
public class BaseItemProviderConfiguration : IEntityTypeConfiguration<BaseItemProvider>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<BaseItemProvider> builder)
{
builder.HasKey(e => new { e.ItemId, e.ProviderId });
builder.HasOne(e => e.Item);
builder.HasIndex(e => new { e.ProviderId, e.ProviderValue, e.ItemId });
}
}
@@ -0,0 +1,18 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// Provides configuration for the BaseItemMetadataField entity.
/// </summary>
public class BaseItemTrailerTypeConfiguration : IEntityTypeConfiguration<BaseItemTrailerType>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<BaseItemTrailerType> builder)
{
builder.HasKey(e => new { e.Id, e.ItemId });
builder.HasOne(e => e.Item);
}
}
@@ -0,0 +1,19 @@
using System;
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// Chapter configuration.
/// </summary>
public class ChapterConfiguration : IEntityTypeConfiguration<Chapter>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<Chapter> builder)
{
builder.HasKey(e => new { e.ItemId, e.ChapterIndex });
builder.HasOne(e => e.Item);
}
}
@@ -0,0 +1,20 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration
{
/// <summary>
/// FluentAPI configuration for the CustomItemDisplayPreferences entity.
/// </summary>
public class CustomItemDisplayPreferencesConfiguration : IEntityTypeConfiguration<CustomItemDisplayPreferences>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<CustomItemDisplayPreferences> builder)
{
builder
.HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key })
.IsUnique();
}
}
}
@@ -0,0 +1,28 @@
using Jellyfin.Data.Entities.Security;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration
{
/// <summary>
/// FluentAPI configuration for the Device entity.
/// </summary>
public class DeviceConfiguration : IEntityTypeConfiguration<Device>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<Device> builder)
{
builder
.HasIndex(entity => new { entity.DeviceId, entity.DateLastActivity });
builder
.HasIndex(entity => new { entity.AccessToken, entity.DateLastActivity });
builder
.HasIndex(entity => new { entity.UserId, entity.DeviceId });
builder
.HasIndex(entity => entity.DeviceId);
}
}
}
@@ -0,0 +1,20 @@
using Jellyfin.Data.Entities.Security;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration
{
/// <summary>
/// FluentAPI configuration for the DeviceOptions entity.
/// </summary>
public class DeviceOptionsConfiguration : IEntityTypeConfiguration<DeviceOptions>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<DeviceOptions> builder)
{
builder
.HasIndex(entity => entity.DeviceId)
.IsUnique();
}
}
}
@@ -0,0 +1,25 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration
{
/// <summary>
/// FluentAPI configuration for the DisplayPreferencesConfiguration entity.
/// </summary>
public class DisplayPreferencesConfiguration : IEntityTypeConfiguration<DisplayPreferences>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<DisplayPreferences> builder)
{
builder
.HasMany(d => d.HomeSections)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder
.HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client })
.IsUnique();
}
}
}
@@ -0,0 +1,19 @@
using System;
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// itemvalues Configuration.
/// </summary>
public class ItemValuesConfiguration : IEntityTypeConfiguration<ItemValue>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<ItemValue> builder)
{
builder.HasKey(e => e.ItemValueId);
builder.HasIndex(e => new { e.Type, e.CleanValue }).IsUnique();
}
}
@@ -0,0 +1,20 @@
using System;
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// itemvalues Configuration.
/// </summary>
public class ItemValuesMapConfiguration : IEntityTypeConfiguration<ItemValueMap>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<ItemValueMap> builder)
{
builder.HasKey(e => new { e.ItemValueId, e.ItemId });
builder.HasOne(e => e.Item);
builder.HasOne(e => e.ItemValue);
}
}
@@ -0,0 +1,22 @@
using System;
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// People configuration.
/// </summary>
public class MediaStreamInfoConfiguration : IEntityTypeConfiguration<MediaStreamInfo>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<MediaStreamInfo> builder)
{
builder.HasKey(e => new { e.ItemId, e.StreamIndex });
builder.HasIndex(e => e.StreamIndex);
builder.HasIndex(e => e.StreamType);
builder.HasIndex(e => new { e.StreamIndex, e.StreamType });
builder.HasIndex(e => new { e.StreamIndex, e.StreamType, e.Language });
}
}
@@ -0,0 +1,22 @@
using System;
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// People configuration.
/// </summary>
public class PeopleBaseItemMapConfiguration : IEntityTypeConfiguration<PeopleBaseItemMap>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<PeopleBaseItemMap> builder)
{
builder.HasKey(e => new { e.ItemId, e.PeopleId });
builder.HasIndex(e => new { e.ItemId, e.SortOrder });
builder.HasIndex(e => new { e.ItemId, e.ListOrder });
builder.HasOne(e => e.Item);
builder.HasOne(e => e.People);
}
}
@@ -0,0 +1,20 @@
using System;
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// People configuration.
/// </summary>
public class PeopleConfiguration : IEntityTypeConfiguration<People>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<People> builder)
{
builder.HasKey(e => e.Id);
builder.HasIndex(e => e.Name);
builder.HasMany(e => e.BaseItems);
}
}
@@ -0,0 +1,24 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration
{
/// <summary>
/// FluentAPI configuration for the Permission entity.
/// </summary>
public class PermissionConfiguration : IEntityTypeConfiguration<Permission>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<Permission> builder)
{
// Used to get a user's permissions or a specific permission for a user.
// Also prevents multiple values being created for a user.
// Filtered over non-null user ids for when other entities (groups, API keys) get permissions
builder
.HasIndex(p => new { p.UserId, p.Kind })
.HasFilter("[UserId] IS NOT NULL")
.IsUnique();
}
}
}
@@ -0,0 +1,21 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration
{
/// <summary>
/// FluentAPI configuration for the Permission entity.
/// </summary>
public class PreferenceConfiguration : IEntityTypeConfiguration<Preference>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<Preference> builder)
{
builder
.HasIndex(p => new { p.UserId, p.Kind })
.HasFilter("[UserId] IS NOT NULL")
.IsUnique();
}
}
}
@@ -0,0 +1,18 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration
{
/// <summary>
/// FluentAPI configuration for the TrickplayInfo entity.
/// </summary>
public class TrickplayInfoConfiguration : IEntityTypeConfiguration<TrickplayInfo>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<TrickplayInfo> builder)
{
builder.HasKey(info => new { info.ItemId, info.Width });
}
}
}
@@ -0,0 +1,56 @@
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration
{
/// <summary>
/// FluentAPI configuration for the User entity.
/// </summary>
public class UserConfiguration : IEntityTypeConfiguration<User>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<User> builder)
{
builder
.Property(user => user.Username)
.UseCollation("NOCASE");
builder
.HasOne(u => u.ProfileImage)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder
.HasMany(u => u.Permissions)
.WithOne()
.HasForeignKey(p => p.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder
.HasMany(u => u.Preferences)
.WithOne()
.HasForeignKey(p => p.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder
.HasMany(u => u.AccessSchedules)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder
.HasMany(u => u.DisplayPreferences)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder
.HasMany(u => u.ItemDisplayPreferences)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder
.HasIndex(entity => entity.Username)
.IsUnique();
}
}
}
@@ -0,0 +1,23 @@
using System;
using Jellyfin.Data.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Jellyfin.Server.Implementations.ModelConfiguration;
/// <summary>
/// FluentAPI configuration for the UserData entity.
/// </summary>
public class UserDataConfiguration : IEntityTypeConfiguration<UserData>
{
/// <inheritdoc/>
public void Configure(EntityTypeBuilder<UserData> builder)
{
builder.HasKey(d => new { d.ItemId, d.UserId, d.CustomDataKey });
builder.HasIndex(d => new { d.ItemId, d.UserId, d.Played });
builder.HasIndex(d => new { d.ItemId, d.UserId, d.PlaybackPositionTicks });
builder.HasIndex(d => new { d.ItemId, d.UserId, d.IsFavorite });
builder.HasIndex(d => new { d.ItemId, d.UserId, d.LastPlayedDate });
builder.HasOne(e => e.Item);
}
}