From 3bc45ff92d207a7c2bb0a57e87b1cec9c3a92964 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Mar 2026 20:14:45 -0500 Subject: [PATCH] Add PostgreSQL EF Core design-time factory and InitialPostgreSql migration (#8) * Initial plan * Add PostgreSQL design-time factory and initial migration for all 29 DbSets Co-authored-by: ZoltyMat <177592743+ZoltyMat@users.noreply.github.com> * Remove accidentally committed build artifacts from PostgreSQL provider Co-authored-by: ZoltyMat <177592743+ZoltyMat@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ZoltyMat <177592743+ZoltyMat@users.noreply.github.com> --- ...260305010333_InitialPostgreSql.Designer.cs | 1690 +++++++++++++++++ .../20260305010333_InitialPostgreSql.cs | 1146 +++++++++++ .../JellyfinDbContextModelSnapshot.cs | 1687 ++++++++++++++++ .../PostgreSqlDesignTimeJellyfinDbFactory.cs | 32 + 4 files changed, 4555 insertions(+) create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/20260305010333_InitialPostgreSql.Designer.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/20260305010333_InitialPostgreSql.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/JellyfinDbContextModelSnapshot.cs create mode 100644 src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/PostgreSqlDesignTimeJellyfinDbFactory.cs diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/20260305010333_InitialPostgreSql.Designer.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/20260305010333_InitialPostgreSql.Designer.cs new file mode 100644 index 000000000..2ac347755 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/20260305010333_InitialPostgreSql.Designer.cs @@ -0,0 +1,1690 @@ +// +using System; +using Jellyfin.Database.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Jellyfin.Database.Providers.PostgreSQL.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20260305010333_InitialPostgreSql")] + partial class InitialPostgreSql + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DayOfWeek") + .HasColumnType("integer"); + + b.Property("EndHour") + .HasColumnType("double precision"); + + b.Property("StartHour") + .HasColumnType("double precision"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LogSeverity") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ParentItemId") + .HasColumnType("uuid"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("Codec") + .HasColumnType("text"); + + b.Property("CodecTag") + .HasColumnType("text"); + + b.Property("Comment") + .HasColumnType("text"); + + b.Property("Filename") + .HasColumnType("text"); + + b.Property("MimeType") + .HasColumnType("text"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Album") + .HasColumnType("text"); + + b.Property("AlbumArtists") + .HasColumnType("text"); + + b.Property("Artists") + .HasColumnType("text"); + + b.Property("Audio") + .HasColumnType("integer"); + + b.Property("ChannelId") + .HasColumnType("uuid"); + + b.Property("CleanName") + .HasColumnType("text"); + + b.Property("CommunityRating") + .HasColumnType("real"); + + b.Property("CriticRating") + .HasColumnType("real"); + + b.Property("CustomRating") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastMediaAdded") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastRefreshed") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastSaved") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("EpisodeTitle") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("ExternalSeriesId") + .HasColumnType("text"); + + b.Property("ExternalServiceId") + .HasColumnType("text"); + + b.Property("ExtraIds") + .HasColumnType("text"); + + b.Property("ExtraType") + .HasColumnType("integer"); + + b.Property("ForcedSortName") + .HasColumnType("text"); + + b.Property("Genres") + .HasColumnType("text"); + + b.Property("Height") + .HasColumnType("integer"); + + b.Property("IndexNumber") + .HasColumnType("integer"); + + b.Property("InheritedParentalRatingSubValue") + .HasColumnType("integer"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("integer"); + + b.Property("IsFolder") + .HasColumnType("boolean"); + + b.Property("IsInMixedFolder") + .HasColumnType("boolean"); + + b.Property("IsLocked") + .HasColumnType("boolean"); + + b.Property("IsMovie") + .HasColumnType("boolean"); + + b.Property("IsRepeat") + .HasColumnType("boolean"); + + b.Property("IsSeries") + .HasColumnType("boolean"); + + b.Property("IsVirtualItem") + .HasColumnType("boolean"); + + b.Property("LUFS") + .HasColumnType("real"); + + b.Property("MediaType") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("NormalizationGain") + .HasColumnType("real"); + + b.Property("OfficialRating") + .HasColumnType("text"); + + b.Property("OriginalTitle") + .HasColumnType("text"); + + b.Property("Overview") + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("ParentIndexNumber") + .HasColumnType("integer"); + + b.Property("Path") + .HasColumnType("text"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("text"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("text"); + + b.Property("PremiereDate") + .HasColumnType("timestamp with time zone"); + + b.Property("PresentationUniqueKey") + .HasColumnType("text"); + + b.Property("PrimaryVersionId") + .HasColumnType("text"); + + b.Property("ProductionLocations") + .HasColumnType("text"); + + b.Property("ProductionYear") + .HasColumnType("integer"); + + b.Property("RunTimeTicks") + .HasColumnType("bigint"); + + b.Property("SeasonId") + .HasColumnType("uuid"); + + b.Property("SeasonName") + .HasColumnType("text"); + + b.Property("SeriesId") + .HasColumnType("uuid"); + + b.Property("SeriesName") + .HasColumnType("text"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("text"); + + b.Property("ShowId") + .HasColumnType("text"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("SortName") + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Studios") + .HasColumnType("text"); + + b.Property("Tagline") + .HasColumnType("text"); + + b.Property("Tags") + .HasColumnType("text"); + + b.Property("TopParentId") + .HasColumnType("uuid"); + + b.Property("TotalBitrate") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("UnratedType") + .HasColumnType("text"); + + b.Property("Width") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + + b.HasData( + new + { + Id = new Guid("00000000-0000-0000-0000-000000000001"), + IsFolder = false, + IsInMixedFolder = false, + IsLocked = false, + IsMovie = false, + IsRepeat = false, + IsSeries = false, + IsVirtualItem = false, + Name = "This is a placeholder item for UserData that has been detacted from its original item", + Type = "PLACEHOLDER" + }); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Blurhash") + .HasColumnType("bytea"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("Height") + .HasColumnType("integer"); + + b.Property("ImageType") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("Width") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ChapterIndex") + .HasColumnType("integer"); + + b.Property("ImageDateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("ImagePath") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("StartPositionTicks") + .HasColumnType("bigint"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChromecastVersion") + .HasColumnType("integer"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("boolean"); + + b.Property("IndexBy") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ScrollDirection") + .HasColumnType("integer"); + + b.Property("ShowBackdrop") + .HasColumnType("boolean"); + + b.Property("ShowSidebar") + .HasColumnType("boolean"); + + b.Property("SkipBackwardLength") + .HasColumnType("integer"); + + b.Property("SkipForwardLength") + .HasColumnType("integer"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DisplayPreferencesId") + .HasColumnType("integer"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("IndexBy") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("RememberIndexing") + .HasColumnType("boolean"); + + b.Property("RememberSorting") + .HasColumnType("boolean"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("ViewType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue"); + + b.HasIndex("Type", "Value") + .IsUnique(); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("uuid"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.KeyframeData", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.PrimitiveCollection("KeyframeTicks") + .HasColumnType("bigint[]"); + + b.Property("TotalDuration") + .HasColumnType("bigint"); + + b.HasKey("ItemId"); + + b.ToTable("KeyframeData"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EndTicks") + .HasColumnType("bigint"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartTicks") + .HasColumnType("bigint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("StreamIndex") + .HasColumnType("integer"); + + b.Property("AspectRatio") + .HasColumnType("text"); + + b.Property("AverageFrameRate") + .HasColumnType("real"); + + b.Property("BitDepth") + .HasColumnType("integer"); + + b.Property("BitRate") + .HasColumnType("integer"); + + b.Property("BlPresentFlag") + .HasColumnType("integer"); + + b.Property("ChannelLayout") + .HasColumnType("text"); + + b.Property("Channels") + .HasColumnType("integer"); + + b.Property("Codec") + .HasColumnType("text"); + + b.Property("CodecTag") + .HasColumnType("text"); + + b.Property("CodecTimeBase") + .HasColumnType("text"); + + b.Property("ColorPrimaries") + .HasColumnType("text"); + + b.Property("ColorSpace") + .HasColumnType("text"); + + b.Property("ColorTransfer") + .HasColumnType("text"); + + b.Property("Comment") + .HasColumnType("text"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("integer"); + + b.Property("DvLevel") + .HasColumnType("integer"); + + b.Property("DvProfile") + .HasColumnType("integer"); + + b.Property("DvVersionMajor") + .HasColumnType("integer"); + + b.Property("DvVersionMinor") + .HasColumnType("integer"); + + b.Property("ElPresentFlag") + .HasColumnType("integer"); + + b.Property("Hdr10PlusPresentFlag") + .HasColumnType("boolean"); + + b.Property("Height") + .HasColumnType("integer"); + + b.Property("IsAnamorphic") + .HasColumnType("boolean"); + + b.Property("IsAvc") + .HasColumnType("boolean"); + + b.Property("IsDefault") + .HasColumnType("boolean"); + + b.Property("IsExternal") + .HasColumnType("boolean"); + + b.Property("IsForced") + .HasColumnType("boolean"); + + b.Property("IsHearingImpaired") + .HasColumnType("boolean"); + + b.Property("IsInterlaced") + .HasColumnType("boolean"); + + b.Property("KeyFrames") + .HasColumnType("text"); + + b.Property("Language") + .HasColumnType("text"); + + b.Property("Level") + .HasColumnType("real"); + + b.Property("NalLengthSize") + .HasColumnType("text"); + + b.Property("Path") + .HasColumnType("text"); + + b.Property("PixelFormat") + .HasColumnType("text"); + + b.Property("Profile") + .HasColumnType("text"); + + b.Property("RealFrameRate") + .HasColumnType("real"); + + b.Property("RefFrames") + .HasColumnType("integer"); + + b.Property("Rotation") + .HasColumnType("integer"); + + b.Property("RpuPresentFlag") + .HasColumnType("integer"); + + b.Property("SampleRate") + .HasColumnType("integer"); + + b.Property("StreamType") + .HasColumnType("integer"); + + b.Property("TimeBase") + .HasColumnType("text"); + + b.Property("Title") + .HasColumnType("text"); + + b.Property("Width") + .HasColumnType("integer"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("PersonType") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("PeopleId") + .HasColumnType("uuid"); + + b.Property("Role") + .HasColumnType("text"); + + b.Property("ListOrder") + .HasColumnType("integer"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.HasKey("ItemId", "PeopleId", "Role"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Kind") + .HasColumnType("integer"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("uuid"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("\"UserId\" IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Kind") + .HasColumnType("integer"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("uuid"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("character varying(65535)"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("\"UserId\" IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastActivity") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("text"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastActivity") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CustomName") + .HasColumnType("text"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("Width") + .HasColumnType("integer"); + + b.Property("Bandwidth") + .HasColumnType("integer"); + + b.Property("Height") + .HasColumnType("integer"); + + b.Property("Interval") + .HasColumnType("integer"); + + b.Property("ThumbnailCount") + .HasColumnType("integer"); + + b.Property("TileHeight") + .HasColumnType("integer"); + + b.Property("TileWidth") + .HasColumnType("integer"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("DisplayCollectionsView") + .HasColumnType("boolean"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("boolean"); + + b.Property("EnableAutoLogin") + .HasColumnType("boolean"); + + b.Property("EnableLocalPassword") + .HasColumnType("boolean"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("boolean"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("boolean"); + + b.Property("HidePlayedInLatest") + .HasColumnType("boolean"); + + b.Property("InternalId") + .HasColumnType("bigint"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("integer"); + + b.Property("LastActivityDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("integer"); + + b.Property("MaxActiveSessions") + .HasColumnType("integer"); + + b.Property("MaxParentalRatingScore") + .HasColumnType("integer"); + + b.Property("MaxParentalRatingSubScore") + .HasColumnType("integer"); + + b.Property("MustUpdatePassword") + .HasColumnType("boolean"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("character varying(65535)"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("boolean"); + + b.Property("RememberAudioSelections") + .HasColumnType("boolean"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("boolean"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("integer"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("SubtitleMode") + .HasColumnType("integer"); + + b.Property("SyncPlayAccess") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("CustomDataKey") + .HasColumnType("text"); + + b.Property("AudioStreamIndex") + .HasColumnType("integer"); + + b.Property("IsFavorite") + .HasColumnType("boolean"); + + b.Property("LastPlayedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Likes") + .HasColumnType("boolean"); + + b.Property("PlayCount") + .HasColumnType("integer"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("bigint"); + + b.Property("Played") + .HasColumnType("boolean"); + + b.Property("Rating") + .HasColumnType("double precision"); + + b.Property("RetentionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("integer"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Parents") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "ParentItem") + .WithMany("Children") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "DirectParent") + .WithMany("DirectChildren") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("DirectParent"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Database.Implementations.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.KeyframeData", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("DirectChildren"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("Parents"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/20260305010333_InitialPostgreSql.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/20260305010333_InitialPostgreSql.cs new file mode 100644 index 000000000..5963a41c6 --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/20260305010333_InitialPostgreSql.cs @@ -0,0 +1,1146 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Jellyfin.Database.Providers.PostgreSQL.Migrations +{ + /// + public partial class InitialPostgreSql : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ActivityLogs", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "character varying(512)", maxLength: 512, nullable: false), + Overview = table.Column(type: "character varying(512)", maxLength: 512, nullable: true), + ShortOverview = table.Column(type: "character varying(512)", maxLength: 512, nullable: true), + Type = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + ItemId = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + DateCreated = table.Column(type: "timestamp with time zone", nullable: false), + LogSeverity = table.Column(type: "integer", nullable: false), + RowVersion = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ActivityLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ApiKeys", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + DateCreated = table.Column(type: "timestamp with time zone", nullable: false), + DateLastActivity = table.Column(type: "timestamp with time zone", nullable: false), + Name = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + AccessToken = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiKeys", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "BaseItems", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Type = table.Column(type: "text", nullable: false), + Data = table.Column(type: "text", nullable: true), + Path = table.Column(type: "text", nullable: true), + StartDate = table.Column(type: "timestamp with time zone", nullable: true), + EndDate = table.Column(type: "timestamp with time zone", nullable: true), + ChannelId = table.Column(type: "uuid", nullable: true), + IsMovie = table.Column(type: "boolean", nullable: false), + CommunityRating = table.Column(type: "real", nullable: true), + CustomRating = table.Column(type: "text", nullable: true), + IndexNumber = table.Column(type: "integer", nullable: true), + IsLocked = table.Column(type: "boolean", nullable: false), + Name = table.Column(type: "text", nullable: true), + OfficialRating = table.Column(type: "text", nullable: true), + MediaType = table.Column(type: "text", nullable: true), + Overview = table.Column(type: "text", nullable: true), + ParentIndexNumber = table.Column(type: "integer", nullable: true), + PremiereDate = table.Column(type: "timestamp with time zone", nullable: true), + ProductionYear = table.Column(type: "integer", nullable: true), + Genres = table.Column(type: "text", nullable: true), + SortName = table.Column(type: "text", nullable: true), + ForcedSortName = table.Column(type: "text", nullable: true), + RunTimeTicks = table.Column(type: "bigint", nullable: true), + DateCreated = table.Column(type: "timestamp with time zone", nullable: true), + DateModified = table.Column(type: "timestamp with time zone", nullable: true), + IsSeries = table.Column(type: "boolean", nullable: false), + EpisodeTitle = table.Column(type: "text", nullable: true), + IsRepeat = table.Column(type: "boolean", nullable: false), + PreferredMetadataLanguage = table.Column(type: "text", nullable: true), + PreferredMetadataCountryCode = table.Column(type: "text", nullable: true), + DateLastRefreshed = table.Column(type: "timestamp with time zone", nullable: true), + DateLastSaved = table.Column(type: "timestamp with time zone", nullable: true), + IsInMixedFolder = table.Column(type: "boolean", nullable: false), + Studios = table.Column(type: "text", nullable: true), + ExternalServiceId = table.Column(type: "text", nullable: true), + Tags = table.Column(type: "text", nullable: true), + IsFolder = table.Column(type: "boolean", nullable: false), + InheritedParentalRatingValue = table.Column(type: "integer", nullable: true), + InheritedParentalRatingSubValue = table.Column(type: "integer", nullable: true), + UnratedType = table.Column(type: "text", nullable: true), + CriticRating = table.Column(type: "real", nullable: true), + CleanName = table.Column(type: "text", nullable: true), + PresentationUniqueKey = table.Column(type: "text", nullable: true), + OriginalTitle = table.Column(type: "text", nullable: true), + PrimaryVersionId = table.Column(type: "text", nullable: true), + DateLastMediaAdded = table.Column(type: "timestamp with time zone", nullable: true), + Album = table.Column(type: "text", nullable: true), + LUFS = table.Column(type: "real", nullable: true), + NormalizationGain = table.Column(type: "real", nullable: true), + IsVirtualItem = table.Column(type: "boolean", nullable: false), + SeriesName = table.Column(type: "text", nullable: true), + SeasonName = table.Column(type: "text", nullable: true), + ExternalSeriesId = table.Column(type: "text", nullable: true), + Tagline = table.Column(type: "text", nullable: true), + ProductionLocations = table.Column(type: "text", nullable: true), + ExtraIds = table.Column(type: "text", nullable: true), + TotalBitrate = table.Column(type: "integer", nullable: true), + ExtraType = table.Column(type: "integer", nullable: true), + Artists = table.Column(type: "text", nullable: true), + AlbumArtists = table.Column(type: "text", nullable: true), + ExternalId = table.Column(type: "text", nullable: true), + SeriesPresentationUniqueKey = table.Column(type: "text", nullable: true), + ShowId = table.Column(type: "text", nullable: true), + OwnerId = table.Column(type: "text", nullable: true), + Width = table.Column(type: "integer", nullable: true), + Height = table.Column(type: "integer", nullable: true), + Size = table.Column(type: "bigint", nullable: true), + Audio = table.Column(type: "integer", nullable: true), + ParentId = table.Column(type: "uuid", nullable: true), + TopParentId = table.Column(type: "uuid", nullable: true), + SeasonId = table.Column(type: "uuid", nullable: true), + SeriesId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItems", x => x.Id); + table.ForeignKey( + name: "FK_BaseItems_BaseItems_ParentId", + column: x => x.ParentId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "CustomItemDisplayPreferences", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: false), + ItemId = table.Column(type: "uuid", nullable: false), + Client = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + Key = table.Column(type: "text", nullable: false), + Value = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CustomItemDisplayPreferences", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "DeviceOptions", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + DeviceId = table.Column(type: "text", nullable: false), + CustomName = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DeviceOptions", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ItemValues", + columns: table => new + { + ItemValueId = table.Column(type: "uuid", nullable: false), + Type = table.Column(type: "integer", nullable: false), + Value = table.Column(type: "text", nullable: false), + CleanValue = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemValues", x => x.ItemValueId); + }); + + migrationBuilder.CreateTable( + name: "MediaSegments", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + ItemId = table.Column(type: "uuid", nullable: false), + Type = table.Column(type: "integer", nullable: false), + EndTicks = table.Column(type: "bigint", nullable: false), + StartTicks = table.Column(type: "bigint", nullable: false), + SegmentProviderId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MediaSegments", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Peoples", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "text", nullable: false), + PersonType = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Peoples", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "TrickplayInfos", + columns: table => new + { + ItemId = table.Column(type: "uuid", nullable: false), + Width = table.Column(type: "integer", nullable: false), + Height = table.Column(type: "integer", nullable: false), + TileWidth = table.Column(type: "integer", nullable: false), + TileHeight = table.Column(type: "integer", nullable: false), + ThumbnailCount = table.Column(type: "integer", nullable: false), + Interval = table.Column(type: "integer", nullable: false), + Bandwidth = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TrickplayInfos", x => new { x.ItemId, x.Width }); + }); + + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Username = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + Password = table.Column(type: "character varying(65535)", maxLength: 65535, nullable: true), + MustUpdatePassword = table.Column(type: "boolean", nullable: false), + AudioLanguagePreference = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), + AuthenticationProviderId = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + PasswordResetProviderId = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + InvalidLoginAttemptCount = table.Column(type: "integer", nullable: false), + LastActivityDate = table.Column(type: "timestamp with time zone", nullable: true), + LastLoginDate = table.Column(type: "timestamp with time zone", nullable: true), + LoginAttemptsBeforeLockout = table.Column(type: "integer", nullable: true), + MaxActiveSessions = table.Column(type: "integer", nullable: false), + SubtitleMode = table.Column(type: "integer", nullable: false), + PlayDefaultAudioTrack = table.Column(type: "boolean", nullable: false), + SubtitleLanguagePreference = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), + DisplayMissingEpisodes = table.Column(type: "boolean", nullable: false), + DisplayCollectionsView = table.Column(type: "boolean", nullable: false), + EnableLocalPassword = table.Column(type: "boolean", nullable: false), + HidePlayedInLatest = table.Column(type: "boolean", nullable: false), + RememberAudioSelections = table.Column(type: "boolean", nullable: false), + RememberSubtitleSelections = table.Column(type: "boolean", nullable: false), + EnableNextEpisodeAutoPlay = table.Column(type: "boolean", nullable: false), + EnableAutoLogin = table.Column(type: "boolean", nullable: false), + EnableUserPreferenceAccess = table.Column(type: "boolean", nullable: false), + MaxParentalRatingScore = table.Column(type: "integer", nullable: true), + MaxParentalRatingSubScore = table.Column(type: "integer", nullable: true), + RemoteClientBitrateLimit = table.Column(type: "integer", nullable: true), + InternalId = table.Column(type: "bigint", nullable: false), + SyncPlayAccess = table.Column(type: "integer", nullable: false), + CastReceiverId = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + RowVersion = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AncestorIds", + columns: table => new + { + ParentItemId = table.Column(type: "uuid", nullable: false), + ItemId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AncestorIds", x => new { x.ItemId, x.ParentItemId }); + table.ForeignKey( + name: "FK_AncestorIds_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AncestorIds_BaseItems_ParentItemId", + column: x => x.ParentItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AttachmentStreamInfos", + columns: table => new + { + ItemId = table.Column(type: "uuid", nullable: false), + Index = table.Column(type: "integer", nullable: false), + Codec = table.Column(type: "text", nullable: true), + CodecTag = table.Column(type: "text", nullable: true), + Comment = table.Column(type: "text", nullable: true), + Filename = table.Column(type: "text", nullable: true), + MimeType = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AttachmentStreamInfos", x => new { x.ItemId, x.Index }); + table.ForeignKey( + name: "FK_AttachmentStreamInfos_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemImageInfos", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Path = table.Column(type: "text", nullable: false), + DateModified = table.Column(type: "timestamp with time zone", nullable: true), + ImageType = table.Column(type: "integer", nullable: false), + Width = table.Column(type: "integer", nullable: false), + Height = table.Column(type: "integer", nullable: false), + Blurhash = table.Column(type: "bytea", nullable: true), + ItemId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemImageInfos", x => x.Id); + table.ForeignKey( + name: "FK_BaseItemImageInfos_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemMetadataFields", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false), + ItemId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemMetadataFields", x => new { x.Id, x.ItemId }); + table.ForeignKey( + name: "FK_BaseItemMetadataFields_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemProviders", + columns: table => new + { + ItemId = table.Column(type: "uuid", nullable: false), + ProviderId = table.Column(type: "text", nullable: false), + ProviderValue = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemProviders", x => new { x.ItemId, x.ProviderId }); + table.ForeignKey( + name: "FK_BaseItemProviders_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BaseItemTrailerTypes", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false), + ItemId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BaseItemTrailerTypes", x => new { x.Id, x.ItemId }); + table.ForeignKey( + name: "FK_BaseItemTrailerTypes_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Chapters", + columns: table => new + { + ItemId = table.Column(type: "uuid", nullable: false), + ChapterIndex = table.Column(type: "integer", nullable: false), + StartPositionTicks = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: true), + ImagePath = table.Column(type: "text", nullable: true), + ImageDateModified = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Chapters", x => new { x.ItemId, x.ChapterIndex }); + table.ForeignKey( + name: "FK_Chapters_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "KeyframeData", + columns: table => new + { + ItemId = table.Column(type: "uuid", nullable: false), + TotalDuration = table.Column(type: "bigint", nullable: false), + KeyframeTicks = table.Column(type: "bigint[]", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_KeyframeData", x => x.ItemId); + table.ForeignKey( + name: "FK_KeyframeData_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "MediaStreamInfos", + columns: table => new + { + ItemId = table.Column(type: "uuid", nullable: false), + StreamIndex = table.Column(type: "integer", nullable: false), + StreamType = table.Column(type: "integer", nullable: false), + Codec = table.Column(type: "text", nullable: true), + Language = table.Column(type: "text", nullable: true), + ChannelLayout = table.Column(type: "text", nullable: true), + Profile = table.Column(type: "text", nullable: true), + AspectRatio = table.Column(type: "text", nullable: true), + Path = table.Column(type: "text", nullable: true), + IsInterlaced = table.Column(type: "boolean", nullable: true), + BitRate = table.Column(type: "integer", nullable: true), + Channels = table.Column(type: "integer", nullable: true), + SampleRate = table.Column(type: "integer", nullable: true), + IsDefault = table.Column(type: "boolean", nullable: false), + IsForced = table.Column(type: "boolean", nullable: false), + IsExternal = table.Column(type: "boolean", nullable: false), + Height = table.Column(type: "integer", nullable: true), + Width = table.Column(type: "integer", nullable: true), + AverageFrameRate = table.Column(type: "real", nullable: true), + RealFrameRate = table.Column(type: "real", nullable: true), + Level = table.Column(type: "real", nullable: true), + PixelFormat = table.Column(type: "text", nullable: true), + BitDepth = table.Column(type: "integer", nullable: true), + IsAnamorphic = table.Column(type: "boolean", nullable: true), + RefFrames = table.Column(type: "integer", nullable: true), + CodecTag = table.Column(type: "text", nullable: true), + Comment = table.Column(type: "text", nullable: true), + NalLengthSize = table.Column(type: "text", nullable: true), + IsAvc = table.Column(type: "boolean", nullable: true), + Title = table.Column(type: "text", nullable: true), + TimeBase = table.Column(type: "text", nullable: true), + CodecTimeBase = table.Column(type: "text", nullable: true), + ColorPrimaries = table.Column(type: "text", nullable: true), + ColorSpace = table.Column(type: "text", nullable: true), + ColorTransfer = table.Column(type: "text", nullable: true), + DvVersionMajor = table.Column(type: "integer", nullable: true), + DvVersionMinor = table.Column(type: "integer", nullable: true), + DvProfile = table.Column(type: "integer", nullable: true), + DvLevel = table.Column(type: "integer", nullable: true), + RpuPresentFlag = table.Column(type: "integer", nullable: true), + ElPresentFlag = table.Column(type: "integer", nullable: true), + BlPresentFlag = table.Column(type: "integer", nullable: true), + DvBlSignalCompatibilityId = table.Column(type: "integer", nullable: true), + IsHearingImpaired = table.Column(type: "boolean", nullable: true), + Rotation = table.Column(type: "integer", nullable: true), + KeyFrames = table.Column(type: "text", nullable: true), + Hdr10PlusPresentFlag = table.Column(type: "boolean", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_MediaStreamInfos", x => new { x.ItemId, x.StreamIndex }); + table.ForeignKey( + name: "FK_MediaStreamInfos_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ItemValuesMap", + columns: table => new + { + ItemId = table.Column(type: "uuid", nullable: false), + ItemValueId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemValuesMap", x => new { x.ItemValueId, x.ItemId }); + table.ForeignKey( + name: "FK_ItemValuesMap_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ItemValuesMap_ItemValues_ItemValueId", + column: x => x.ItemValueId, + principalTable: "ItemValues", + principalColumn: "ItemValueId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "PeopleBaseItemMap", + columns: table => new + { + Role = table.Column(type: "text", nullable: false), + ItemId = table.Column(type: "uuid", nullable: false), + PeopleId = table.Column(type: "uuid", nullable: false), + SortOrder = table.Column(type: "integer", nullable: true), + ListOrder = table.Column(type: "integer", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PeopleBaseItemMap", x => new { x.ItemId, x.PeopleId, x.Role }); + table.ForeignKey( + name: "FK_PeopleBaseItemMap_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_PeopleBaseItemMap_Peoples_PeopleId", + column: x => x.PeopleId, + principalTable: "Peoples", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AccessSchedules", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: false), + DayOfWeek = table.Column(type: "integer", nullable: false), + StartHour = table.Column(type: "double precision", nullable: false), + EndHour = table.Column(type: "double precision", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AccessSchedules", x => x.Id); + table.ForeignKey( + name: "FK_AccessSchedules_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Devices", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: false), + AccessToken = table.Column(type: "text", nullable: false), + AppName = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + AppVersion = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + DeviceName = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + DeviceId = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + IsActive = table.Column(type: "boolean", nullable: false), + DateCreated = table.Column(type: "timestamp with time zone", nullable: false), + DateModified = table.Column(type: "timestamp with time zone", nullable: false), + DateLastActivity = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Devices", x => x.Id); + table.ForeignKey( + name: "FK_Devices_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "DisplayPreferences", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: false), + ItemId = table.Column(type: "uuid", nullable: false), + Client = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + ShowSidebar = table.Column(type: "boolean", nullable: false), + ShowBackdrop = table.Column(type: "boolean", nullable: false), + ScrollDirection = table.Column(type: "integer", nullable: false), + IndexBy = table.Column(type: "integer", nullable: true), + SkipForwardLength = table.Column(type: "integer", nullable: false), + SkipBackwardLength = table.Column(type: "integer", nullable: false), + ChromecastVersion = table.Column(type: "integer", nullable: false), + EnableNextVideoInfoOverlay = table.Column(type: "boolean", nullable: false), + DashboardTheme = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + TvHome = table.Column(type: "character varying(32)", maxLength: 32, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_DisplayPreferences_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ImageInfos", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: true), + Path = table.Column(type: "character varying(512)", maxLength: 512, nullable: false), + LastModified = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ImageInfos", x => x.Id); + table.ForeignKey( + name: "FK_ImageInfos_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ItemDisplayPreferences", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: false), + ItemId = table.Column(type: "uuid", nullable: false), + Client = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + ViewType = table.Column(type: "integer", nullable: false), + RememberIndexing = table.Column(type: "boolean", nullable: false), + IndexBy = table.Column(type: "integer", nullable: true), + RememberSorting = table.Column(type: "boolean", nullable: false), + SortBy = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + SortOrder = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemDisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_ItemDisplayPreferences_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Permissions", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: true), + Kind = table.Column(type: "integer", nullable: false), + Value = table.Column(type: "boolean", nullable: false), + RowVersion = table.Column(type: "bigint", nullable: false), + Permission_Permissions_Guid = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Permissions", x => x.Id); + table.ForeignKey( + name: "FK_Permissions_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Preferences", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: true), + Kind = table.Column(type: "integer", nullable: false), + Value = table.Column(type: "character varying(65535)", maxLength: 65535, nullable: false), + RowVersion = table.Column(type: "bigint", nullable: false), + Preference_Preferences_Guid = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Preferences", x => x.Id); + table.ForeignKey( + name: "FK_Preferences_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserData", + columns: table => new + { + CustomDataKey = table.Column(type: "text", nullable: false), + ItemId = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + Rating = table.Column(type: "double precision", nullable: true), + PlaybackPositionTicks = table.Column(type: "bigint", nullable: false), + PlayCount = table.Column(type: "integer", nullable: false), + IsFavorite = table.Column(type: "boolean", nullable: false), + LastPlayedDate = table.Column(type: "timestamp with time zone", nullable: true), + Played = table.Column(type: "boolean", nullable: false), + AudioStreamIndex = table.Column(type: "integer", nullable: true), + SubtitleStreamIndex = table.Column(type: "integer", nullable: true), + Likes = table.Column(type: "boolean", nullable: true), + RetentionDate = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_UserData", x => new { x.ItemId, x.UserId, x.CustomDataKey }); + table.ForeignKey( + name: "FK_UserData_BaseItems_ItemId", + column: x => x.ItemId, + principalTable: "BaseItems", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_UserData_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "HomeSection", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + DisplayPreferencesId = table.Column(type: "integer", nullable: false), + Order = table.Column(type: "integer", nullable: false), + Type = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_HomeSection", x => x.Id); + table.ForeignKey( + name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", + column: x => x.DisplayPreferencesId, + principalTable: "DisplayPreferences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + table: "BaseItems", + columns: new[] { "Id", "Album", "AlbumArtists", "Artists", "Audio", "ChannelId", "CleanName", "CommunityRating", "CriticRating", "CustomRating", "Data", "DateCreated", "DateLastMediaAdded", "DateLastRefreshed", "DateLastSaved", "DateModified", "EndDate", "EpisodeTitle", "ExternalId", "ExternalSeriesId", "ExternalServiceId", "ExtraIds", "ExtraType", "ForcedSortName", "Genres", "Height", "IndexNumber", "InheritedParentalRatingSubValue", "InheritedParentalRatingValue", "IsFolder", "IsInMixedFolder", "IsLocked", "IsMovie", "IsRepeat", "IsSeries", "IsVirtualItem", "LUFS", "MediaType", "Name", "NormalizationGain", "OfficialRating", "OriginalTitle", "Overview", "OwnerId", "ParentId", "ParentIndexNumber", "Path", "PreferredMetadataCountryCode", "PreferredMetadataLanguage", "PremiereDate", "PresentationUniqueKey", "PrimaryVersionId", "ProductionLocations", "ProductionYear", "RunTimeTicks", "SeasonId", "SeasonName", "SeriesId", "SeriesName", "SeriesPresentationUniqueKey", "ShowId", "Size", "SortName", "StartDate", "Studios", "Tagline", "Tags", "TopParentId", "TotalBitrate", "Type", "UnratedType", "Width" }, + values: new object[] { new Guid("00000000-0000-0000-0000-000000000001"), null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, false, false, false, false, false, false, false, null, null, "This is a placeholder item for UserData that has been detacted from its original item", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "PLACEHOLDER", null, null }); + + migrationBuilder.CreateIndex( + name: "IX_AccessSchedules_UserId", + table: "AccessSchedules", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_ActivityLogs_DateCreated", + table: "ActivityLogs", + column: "DateCreated"); + + migrationBuilder.CreateIndex( + name: "IX_AncestorIds_ParentItemId", + table: "AncestorIds", + column: "ParentItemId"); + + migrationBuilder.CreateIndex( + name: "IX_ApiKeys_AccessToken", + table: "ApiKeys", + column: "AccessToken", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemImageInfos_ItemId", + table: "BaseItemImageInfos", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemMetadataFields_ItemId", + table: "BaseItemMetadataFields", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemProviders_ProviderId_ProviderValue_ItemId", + table: "BaseItemProviders", + columns: new[] { "ProviderId", "ProviderValue", "ItemId" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Id_Type_IsFolder_IsVirtualItem", + table: "BaseItems", + columns: new[] { "Id", "Type", "IsFolder", "IsVirtualItem" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_IsFolder_TopParentId_IsVirtualItem_PresentationUn~", + table: "BaseItems", + columns: new[] { "IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_MediaType_TopParentId_IsVirtualItem_PresentationU~", + table: "BaseItems", + columns: new[] { "MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_ParentId", + table: "BaseItems", + column: "ParentId"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Path", + table: "BaseItems", + column: "Path"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_PresentationUniqueKey", + table: "BaseItems", + column: "PresentationUniqueKey"); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_TopParentId_Id", + table: "BaseItems", + columns: new[] { "TopParentId", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_SeriesPresentationUniqueKey_IsFolder_IsVirtu~", + table: "BaseItems", + columns: new[] { "Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_SeriesPresentationUniqueKey_PresentationUniq~", + table: "BaseItems", + columns: new[] { "Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_Id", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "Id" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_IsVirtualItem_PresentationUnique~", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_PresentationUniqueKey", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "PresentationUniqueKey" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItems_Type_TopParentId_StartDate", + table: "BaseItems", + columns: new[] { "Type", "TopParentId", "StartDate" }); + + migrationBuilder.CreateIndex( + name: "IX_BaseItemTrailerTypes_ItemId", + table: "BaseItemTrailerTypes", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_CustomItemDisplayPreferences_UserId_ItemId_Client_Key", + table: "CustomItemDisplayPreferences", + columns: new[] { "UserId", "ItemId", "Client", "Key" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_DeviceOptions_DeviceId", + table: "DeviceOptions", + column: "DeviceId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Devices_AccessToken_DateLastActivity", + table: "Devices", + columns: new[] { "AccessToken", "DateLastActivity" }); + + migrationBuilder.CreateIndex( + name: "IX_Devices_DeviceId", + table: "Devices", + column: "DeviceId"); + + migrationBuilder.CreateIndex( + name: "IX_Devices_DeviceId_DateLastActivity", + table: "Devices", + columns: new[] { "DeviceId", "DateLastActivity" }); + + migrationBuilder.CreateIndex( + name: "IX_Devices_UserId_DeviceId", + table: "Devices", + columns: new[] { "UserId", "DeviceId" }); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId_ItemId_Client", + table: "DisplayPreferences", + columns: new[] { "UserId", "ItemId", "Client" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_HomeSection_DisplayPreferencesId", + table: "HomeSection", + column: "DisplayPreferencesId"); + + migrationBuilder.CreateIndex( + name: "IX_ImageInfos_UserId", + table: "ImageInfos", + column: "UserId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ItemDisplayPreferences_UserId", + table: "ItemDisplayPreferences", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_ItemValues_Type_CleanValue", + table: "ItemValues", + columns: new[] { "Type", "CleanValue" }); + + migrationBuilder.CreateIndex( + name: "IX_ItemValues_Type_Value", + table: "ItemValues", + columns: new[] { "Type", "Value" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ItemValuesMap_ItemId", + table: "ItemValuesMap", + column: "ItemId"); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamIndex", + table: "MediaStreamInfos", + column: "StreamIndex"); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamIndex_StreamType", + table: "MediaStreamInfos", + columns: new[] { "StreamIndex", "StreamType" }); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamIndex_StreamType_Language", + table: "MediaStreamInfos", + columns: new[] { "StreamIndex", "StreamType", "Language" }); + + migrationBuilder.CreateIndex( + name: "IX_MediaStreamInfos_StreamType", + table: "MediaStreamInfos", + column: "StreamType"); + + migrationBuilder.CreateIndex( + name: "IX_PeopleBaseItemMap_ItemId_ListOrder", + table: "PeopleBaseItemMap", + columns: new[] { "ItemId", "ListOrder" }); + + migrationBuilder.CreateIndex( + name: "IX_PeopleBaseItemMap_ItemId_SortOrder", + table: "PeopleBaseItemMap", + columns: new[] { "ItemId", "SortOrder" }); + + migrationBuilder.CreateIndex( + name: "IX_PeopleBaseItemMap_PeopleId", + table: "PeopleBaseItemMap", + column: "PeopleId"); + + migrationBuilder.CreateIndex( + name: "IX_Peoples_Name", + table: "Peoples", + column: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_Permissions_UserId_Kind", + table: "Permissions", + columns: new[] { "UserId", "Kind" }, + unique: true, + filter: "\"UserId\" IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_Preferences_UserId_Kind", + table: "Preferences", + columns: new[] { "UserId", "Kind" }, + unique: true, + filter: "\"UserId\" IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_IsFavorite", + table: "UserData", + columns: new[] { "ItemId", "UserId", "IsFavorite" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_LastPlayedDate", + table: "UserData", + columns: new[] { "ItemId", "UserId", "LastPlayedDate" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_PlaybackPositionTicks", + table: "UserData", + columns: new[] { "ItemId", "UserId", "PlaybackPositionTicks" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_ItemId_UserId_Played", + table: "UserData", + columns: new[] { "ItemId", "UserId", "Played" }); + + migrationBuilder.CreateIndex( + name: "IX_UserData_UserId", + table: "UserData", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_Users_Username", + table: "Users", + column: "Username", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AccessSchedules"); + + migrationBuilder.DropTable( + name: "ActivityLogs"); + + migrationBuilder.DropTable( + name: "AncestorIds"); + + migrationBuilder.DropTable( + name: "ApiKeys"); + + migrationBuilder.DropTable( + name: "AttachmentStreamInfos"); + + migrationBuilder.DropTable( + name: "BaseItemImageInfos"); + + migrationBuilder.DropTable( + name: "BaseItemMetadataFields"); + + migrationBuilder.DropTable( + name: "BaseItemProviders"); + + migrationBuilder.DropTable( + name: "BaseItemTrailerTypes"); + + migrationBuilder.DropTable( + name: "Chapters"); + + migrationBuilder.DropTable( + name: "CustomItemDisplayPreferences"); + + migrationBuilder.DropTable( + name: "DeviceOptions"); + + migrationBuilder.DropTable( + name: "Devices"); + + migrationBuilder.DropTable( + name: "HomeSection"); + + migrationBuilder.DropTable( + name: "ImageInfos"); + + migrationBuilder.DropTable( + name: "ItemDisplayPreferences"); + + migrationBuilder.DropTable( + name: "ItemValuesMap"); + + migrationBuilder.DropTable( + name: "KeyframeData"); + + migrationBuilder.DropTable( + name: "MediaSegments"); + + migrationBuilder.DropTable( + name: "MediaStreamInfos"); + + migrationBuilder.DropTable( + name: "PeopleBaseItemMap"); + + migrationBuilder.DropTable( + name: "Permissions"); + + migrationBuilder.DropTable( + name: "Preferences"); + + migrationBuilder.DropTable( + name: "TrickplayInfos"); + + migrationBuilder.DropTable( + name: "UserData"); + + migrationBuilder.DropTable( + name: "DisplayPreferences"); + + migrationBuilder.DropTable( + name: "ItemValues"); + + migrationBuilder.DropTable( + name: "Peoples"); + + migrationBuilder.DropTable( + name: "BaseItems"); + + migrationBuilder.DropTable( + name: "Users"); + } + } +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/JellyfinDbContextModelSnapshot.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/JellyfinDbContextModelSnapshot.cs new file mode 100644 index 000000000..ceb44c7ef --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/Migrations/JellyfinDbContextModelSnapshot.cs @@ -0,0 +1,1687 @@ +// +using System; +using Jellyfin.Database.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Jellyfin.Database.Providers.PostgreSQL.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + partial class JellyfinDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DayOfWeek") + .HasColumnType("integer"); + + b.Property("EndHour") + .HasColumnType("double precision"); + + b.Property("StartHour") + .HasColumnType("double precision"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("ItemId") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LogSeverity") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Overview") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property("ShortOverview") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ParentItemId") + .HasColumnType("uuid"); + + b.HasKey("ItemId", "ParentItemId"); + + b.HasIndex("ParentItemId"); + + b.ToTable("AncestorIds"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("Codec") + .HasColumnType("text"); + + b.Property("CodecTag") + .HasColumnType("text"); + + b.Property("Comment") + .HasColumnType("text"); + + b.Property("Filename") + .HasColumnType("text"); + + b.Property("MimeType") + .HasColumnType("text"); + + b.HasKey("ItemId", "Index"); + + b.ToTable("AttachmentStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Album") + .HasColumnType("text"); + + b.Property("AlbumArtists") + .HasColumnType("text"); + + b.Property("Artists") + .HasColumnType("text"); + + b.Property("Audio") + .HasColumnType("integer"); + + b.Property("ChannelId") + .HasColumnType("uuid"); + + b.Property("CleanName") + .HasColumnType("text"); + + b.Property("CommunityRating") + .HasColumnType("real"); + + b.Property("CriticRating") + .HasColumnType("real"); + + b.Property("CustomRating") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastMediaAdded") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastRefreshed") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastSaved") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("EpisodeTitle") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("ExternalSeriesId") + .HasColumnType("text"); + + b.Property("ExternalServiceId") + .HasColumnType("text"); + + b.Property("ExtraIds") + .HasColumnType("text"); + + b.Property("ExtraType") + .HasColumnType("integer"); + + b.Property("ForcedSortName") + .HasColumnType("text"); + + b.Property("Genres") + .HasColumnType("text"); + + b.Property("Height") + .HasColumnType("integer"); + + b.Property("IndexNumber") + .HasColumnType("integer"); + + b.Property("InheritedParentalRatingSubValue") + .HasColumnType("integer"); + + b.Property("InheritedParentalRatingValue") + .HasColumnType("integer"); + + b.Property("IsFolder") + .HasColumnType("boolean"); + + b.Property("IsInMixedFolder") + .HasColumnType("boolean"); + + b.Property("IsLocked") + .HasColumnType("boolean"); + + b.Property("IsMovie") + .HasColumnType("boolean"); + + b.Property("IsRepeat") + .HasColumnType("boolean"); + + b.Property("IsSeries") + .HasColumnType("boolean"); + + b.Property("IsVirtualItem") + .HasColumnType("boolean"); + + b.Property("LUFS") + .HasColumnType("real"); + + b.Property("MediaType") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("NormalizationGain") + .HasColumnType("real"); + + b.Property("OfficialRating") + .HasColumnType("text"); + + b.Property("OriginalTitle") + .HasColumnType("text"); + + b.Property("Overview") + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("text"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("ParentIndexNumber") + .HasColumnType("integer"); + + b.Property("Path") + .HasColumnType("text"); + + b.Property("PreferredMetadataCountryCode") + .HasColumnType("text"); + + b.Property("PreferredMetadataLanguage") + .HasColumnType("text"); + + b.Property("PremiereDate") + .HasColumnType("timestamp with time zone"); + + b.Property("PresentationUniqueKey") + .HasColumnType("text"); + + b.Property("PrimaryVersionId") + .HasColumnType("text"); + + b.Property("ProductionLocations") + .HasColumnType("text"); + + b.Property("ProductionYear") + .HasColumnType("integer"); + + b.Property("RunTimeTicks") + .HasColumnType("bigint"); + + b.Property("SeasonId") + .HasColumnType("uuid"); + + b.Property("SeasonName") + .HasColumnType("text"); + + b.Property("SeriesId") + .HasColumnType("uuid"); + + b.Property("SeriesName") + .HasColumnType("text"); + + b.Property("SeriesPresentationUniqueKey") + .HasColumnType("text"); + + b.Property("ShowId") + .HasColumnType("text"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("SortName") + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Studios") + .HasColumnType("text"); + + b.Property("Tagline") + .HasColumnType("text"); + + b.Property("Tags") + .HasColumnType("text"); + + b.Property("TopParentId") + .HasColumnType("uuid"); + + b.Property("TotalBitrate") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("UnratedType") + .HasColumnType("text"); + + b.Property("Width") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("Path"); + + b.HasIndex("PresentationUniqueKey"); + + b.HasIndex("TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "Id"); + + b.HasIndex("Type", "TopParentId", "PresentationUniqueKey"); + + b.HasIndex("Type", "TopParentId", "StartDate"); + + b.HasIndex("Id", "Type", "IsFolder", "IsVirtualItem"); + + b.HasIndex("MediaType", "TopParentId", "IsVirtualItem", "PresentationUniqueKey"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "IsFolder", "IsVirtualItem"); + + b.HasIndex("Type", "SeriesPresentationUniqueKey", "PresentationUniqueKey", "SortName"); + + b.HasIndex("IsFolder", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.HasIndex("Type", "TopParentId", "IsVirtualItem", "PresentationUniqueKey", "DateCreated"); + + b.ToTable("BaseItems"); + + b.HasData( + new + { + Id = new Guid("00000000-0000-0000-0000-000000000001"), + IsFolder = false, + IsInMixedFolder = false, + IsLocked = false, + IsMovie = false, + IsRepeat = false, + IsSeries = false, + IsVirtualItem = false, + Name = "This is a placeholder item for UserData that has been detacted from its original item", + Type = "PLACEHOLDER" + }); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Blurhash") + .HasColumnType("bytea"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("Height") + .HasColumnType("integer"); + + b.Property("ImageType") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("Width") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemMetadataFields"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("text"); + + b.Property("ProviderValue") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ItemId", "ProviderId"); + + b.HasIndex("ProviderId", "ProviderValue", "ItemId"); + + b.ToTable("BaseItemProviders"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.HasKey("Id", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("BaseItemTrailerTypes"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ChapterIndex") + .HasColumnType("integer"); + + b.Property("ImageDateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("ImagePath") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("StartPositionTicks") + .HasColumnType("bigint"); + + b.HasKey("ItemId", "ChapterIndex"); + + b.ToTable("Chapters"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.CustomItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChromecastVersion") + .HasColumnType("integer"); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("boolean"); + + b.Property("IndexBy") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ScrollDirection") + .HasColumnType("integer"); + + b.Property("ShowBackdrop") + .HasColumnType("boolean"); + + b.Property("ShowSidebar") + .HasColumnType("boolean"); + + b.Property("SkipBackwardLength") + .HasColumnType("integer"); + + b.Property("SkipForwardLength") + .HasColumnType("integer"); + + b.Property("TvHome") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DisplayPreferencesId") + .HasColumnType("integer"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("IndexBy") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("RememberIndexing") + .HasColumnType("boolean"); + + b.Property("RememberSorting") + .HasColumnType("boolean"); + + b.Property("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("ViewType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Property("ItemValueId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CleanValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ItemValueId"); + + b.HasIndex("Type", "CleanValue"); + + b.HasIndex("Type", "Value") + .IsUnique(); + + b.ToTable("ItemValues"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.Property("ItemValueId") + .HasColumnType("uuid"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.HasKey("ItemValueId", "ItemId"); + + b.HasIndex("ItemId"); + + b.ToTable("ItemValuesMap"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.KeyframeData", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.PrimitiveCollection("KeyframeTicks") + .HasColumnType("bigint[]"); + + b.Property("TotalDuration") + .HasColumnType("bigint"); + + b.HasKey("ItemId"); + + b.ToTable("KeyframeData"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaSegment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EndTicks") + .HasColumnType("bigint"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("SegmentProviderId") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartTicks") + .HasColumnType("bigint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("MediaSegments"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("StreamIndex") + .HasColumnType("integer"); + + b.Property("AspectRatio") + .HasColumnType("text"); + + b.Property("AverageFrameRate") + .HasColumnType("real"); + + b.Property("BitDepth") + .HasColumnType("integer"); + + b.Property("BitRate") + .HasColumnType("integer"); + + b.Property("BlPresentFlag") + .HasColumnType("integer"); + + b.Property("ChannelLayout") + .HasColumnType("text"); + + b.Property("Channels") + .HasColumnType("integer"); + + b.Property("Codec") + .HasColumnType("text"); + + b.Property("CodecTag") + .HasColumnType("text"); + + b.Property("CodecTimeBase") + .HasColumnType("text"); + + b.Property("ColorPrimaries") + .HasColumnType("text"); + + b.Property("ColorSpace") + .HasColumnType("text"); + + b.Property("ColorTransfer") + .HasColumnType("text"); + + b.Property("Comment") + .HasColumnType("text"); + + b.Property("DvBlSignalCompatibilityId") + .HasColumnType("integer"); + + b.Property("DvLevel") + .HasColumnType("integer"); + + b.Property("DvProfile") + .HasColumnType("integer"); + + b.Property("DvVersionMajor") + .HasColumnType("integer"); + + b.Property("DvVersionMinor") + .HasColumnType("integer"); + + b.Property("ElPresentFlag") + .HasColumnType("integer"); + + b.Property("Hdr10PlusPresentFlag") + .HasColumnType("boolean"); + + b.Property("Height") + .HasColumnType("integer"); + + b.Property("IsAnamorphic") + .HasColumnType("boolean"); + + b.Property("IsAvc") + .HasColumnType("boolean"); + + b.Property("IsDefault") + .HasColumnType("boolean"); + + b.Property("IsExternal") + .HasColumnType("boolean"); + + b.Property("IsForced") + .HasColumnType("boolean"); + + b.Property("IsHearingImpaired") + .HasColumnType("boolean"); + + b.Property("IsInterlaced") + .HasColumnType("boolean"); + + b.Property("KeyFrames") + .HasColumnType("text"); + + b.Property("Language") + .HasColumnType("text"); + + b.Property("Level") + .HasColumnType("real"); + + b.Property("NalLengthSize") + .HasColumnType("text"); + + b.Property("Path") + .HasColumnType("text"); + + b.Property("PixelFormat") + .HasColumnType("text"); + + b.Property("Profile") + .HasColumnType("text"); + + b.Property("RealFrameRate") + .HasColumnType("real"); + + b.Property("RefFrames") + .HasColumnType("integer"); + + b.Property("Rotation") + .HasColumnType("integer"); + + b.Property("RpuPresentFlag") + .HasColumnType("integer"); + + b.Property("SampleRate") + .HasColumnType("integer"); + + b.Property("StreamType") + .HasColumnType("integer"); + + b.Property("TimeBase") + .HasColumnType("text"); + + b.Property("Title") + .HasColumnType("text"); + + b.Property("Width") + .HasColumnType("integer"); + + b.HasKey("ItemId", "StreamIndex"); + + b.HasIndex("StreamIndex"); + + b.HasIndex("StreamType"); + + b.HasIndex("StreamIndex", "StreamType"); + + b.HasIndex("StreamIndex", "StreamType", "Language"); + + b.ToTable("MediaStreamInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("PersonType") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Peoples"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("PeopleId") + .HasColumnType("uuid"); + + b.Property("Role") + .HasColumnType("text"); + + b.Property("ListOrder") + .HasColumnType("integer"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.HasKey("ItemId", "PeopleId", "Role"); + + b.HasIndex("PeopleId"); + + b.HasIndex("ItemId", "ListOrder"); + + b.HasIndex("ItemId", "SortOrder"); + + b.ToTable("PeopleBaseItemMap"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Kind") + .HasColumnType("integer"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("uuid"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("\"UserId\" IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Kind") + .HasColumnType("integer"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("uuid"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("character varying(65535)"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("\"UserId\" IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.ApiKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastActivity") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("text"); + + b.Property("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateLastActivity") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.DeviceOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CustomName") + .HasColumnType("text"); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.TrickplayInfo", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("Width") + .HasColumnType("integer"); + + b.Property("Bandwidth") + .HasColumnType("integer"); + + b.Property("Height") + .HasColumnType("integer"); + + b.Property("Interval") + .HasColumnType("integer"); + + b.Property("ThumbnailCount") + .HasColumnType("integer"); + + b.Property("TileHeight") + .HasColumnType("integer"); + + b.Property("TileWidth") + .HasColumnType("integer"); + + b.HasKey("ItemId", "Width"); + + b.ToTable("TrickplayInfos"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CastReceiverId") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("DisplayCollectionsView") + .HasColumnType("boolean"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("boolean"); + + b.Property("EnableAutoLogin") + .HasColumnType("boolean"); + + b.Property("EnableLocalPassword") + .HasColumnType("boolean"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("boolean"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("boolean"); + + b.Property("HidePlayedInLatest") + .HasColumnType("boolean"); + + b.Property("InternalId") + .HasColumnType("bigint"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("integer"); + + b.Property("LastActivityDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("integer"); + + b.Property("MaxActiveSessions") + .HasColumnType("integer"); + + b.Property("MaxParentalRatingScore") + .HasColumnType("integer"); + + b.Property("MaxParentalRatingSubScore") + .HasColumnType("integer"); + + b.Property("MustUpdatePassword") + .HasColumnType("boolean"); + + b.Property("Password") + .HasMaxLength(65535) + .HasColumnType("character varying(65535)"); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("boolean"); + + b.Property("RememberAudioSelections") + .HasColumnType("boolean"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("boolean"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("integer"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("bigint"); + + b.Property("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("SubtitleMode") + .HasColumnType("integer"); + + b.Property("SyncPlayAccess") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("CustomDataKey") + .HasColumnType("text"); + + b.Property("AudioStreamIndex") + .HasColumnType("integer"); + + b.Property("IsFavorite") + .HasColumnType("boolean"); + + b.Property("LastPlayedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Likes") + .HasColumnType("boolean"); + + b.Property("PlayCount") + .HasColumnType("integer"); + + b.Property("PlaybackPositionTicks") + .HasColumnType("bigint"); + + b.Property("Played") + .HasColumnType("boolean"); + + b.Property("Rating") + .HasColumnType("double precision"); + + b.Property("RetentionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SubtitleStreamIndex") + .HasColumnType("integer"); + + b.HasKey("ItemId", "UserId", "CustomDataKey"); + + b.HasIndex("UserId"); + + b.HasIndex("ItemId", "UserId", "IsFavorite"); + + b.HasIndex("ItemId", "UserId", "LastPlayedDate"); + + b.HasIndex("ItemId", "UserId", "PlaybackPositionTicks"); + + b.HasIndex("ItemId", "UserId", "Played"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AncestorId", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Parents") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "ParentItem") + .WithMany("Children") + .HasForeignKey("ParentItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ParentItem"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.AttachmentStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "DirectParent") + .WithMany("DirectChildren") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("DirectParent"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Images") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemMetadataField", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("LockedFields") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemProvider", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Provider") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemTrailerType", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("TrailerTypes") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Chapter", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Chapters") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Database.Implementations.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValueMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("ItemValues") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.ItemValue", "ItemValue") + .WithMany("BaseItemsMap") + .HasForeignKey("ItemValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemValue"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.KeyframeData", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany() + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.MediaStreamInfo", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("MediaStreams") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.PeopleBaseItemMap", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("Peoples") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.People", "People") + .WithMany("BaseItems") + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("People"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Permission", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Preference", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.UserData", b => + { + b.HasOne("Jellyfin.Database.Implementations.Entities.BaseItemEntity", "Item") + .WithMany("UserData") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Jellyfin.Database.Implementations.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.BaseItemEntity", b => + { + b.Navigation("Chapters"); + + b.Navigation("Children"); + + b.Navigation("DirectChildren"); + + b.Navigation("Images"); + + b.Navigation("ItemValues"); + + b.Navigation("LockedFields"); + + b.Navigation("MediaStreams"); + + b.Navigation("Parents"); + + b.Navigation("Peoples"); + + b.Navigation("Provider"); + + b.Navigation("TrailerTypes"); + + b.Navigation("UserData"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.ItemValue", b => + { + b.Navigation("BaseItemsMap"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.People", b => + { + b.Navigation("BaseItems"); + }); + + modelBuilder.Entity("Jellyfin.Database.Implementations.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/PostgreSqlDesignTimeJellyfinDbFactory.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/PostgreSqlDesignTimeJellyfinDbFactory.cs new file mode 100644 index 000000000..342d0693b --- /dev/null +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.PostgreSQL/PostgreSqlDesignTimeJellyfinDbFactory.cs @@ -0,0 +1,32 @@ +using System; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Locking; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Jellyfin.Database.Providers.PostgreSQL; + +/// +/// The design time factory for using PostgreSQL. +/// This is only used for the creation of migrations and not during runtime. +/// +internal sealed class PostgreSqlDesignTimeJellyfinDbFactory : IDesignTimeDbContextFactory +{ + /// + public JellyfinDbContext CreateDbContext(string[] args) + { + var connectionString = + Environment.GetEnvironmentVariable("POSTGRES_CONNECTION_STRING") + ?? "Host=localhost;Database=jellyfin;Username=postgres;Password=postgres"; + + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseNpgsql(connectionString, o => o.MigrationsAssembly(GetType().Assembly)); + + return new JellyfinDbContext( + optionsBuilder.Options, + NullLogger.Instance, + new PostgreSqlDatabaseProvider(), + new NoLockBehavior(NullLogger.Instance)); + } +}