Files
pgsql-jellyfin/docs/SCHEMA_CONVERSION_GUIDE.md
T
wjones e67c191843 Add comprehensive documentation for PostgreSQL schema conversion
- Introduced DATABASE_SCHEMA_MISMATCH_REPORT.md to detail critical mismatches between SQL schema and C# code configurations, highlighting issues with naming conventions and potential runtime failures.
- Created SCHEMA_COLUMN_CONVERSION_REFERENCE.md to provide a reference for column name conversions from PascalCase to snake_case across all tables.
- Developed SCHEMA_CONVERSION_GUIDE.md outlining the conversion strategy for the SQL schema, including authoritative table mappings, column naming rules, and a validation checklist to ensure accuracy in the conversion process.
2026-05-04 10:16:17 -04:00

183 lines
7.4 KiB
Markdown

# SQL Schema Conversion Guide - PascalCase to snake_case
## Authoritative Table Mappings (from PostgresDatabaseProvider.OnModelCreating)
### Activity Log Schema
| Current (SQL) | Target (C#/PostgreSQL) | Entity Class |
|--------------|------------------------|--------------|
| `"ActivityLogs"` | `activity_logs` | `ActivityLog` |
### Authentication Schema
| Current (SQL) | Target (C#/PostgreSQL) | Entity Class |
|--------------|------------------------|--------------|
| `"ApiKeys"` | `api_keys` | `ApiKey` |
| `"Devices"` | `devices` | `Device` |
| `"DeviceOptions"` | `device_options` | `DeviceOptions` |
### Display Preferences Schema
| Current (SQL) | Target (C#/PostgreSQL) | Entity Class |
|--------------|------------------------|--------------|
| `"DisplayPreferences"` | `display_preferences` | `DisplayPreferences` |
| `"ItemDisplayPreferences"` | `item_display_preferences` | `ItemDisplayPreferences` |
| `"CustomItemDisplayPreferences"` | `custom_item_display_preferences` | `CustomItemDisplayPreferences` |
| `"HomeSections"` | `home_sections` | `HomeSection` |
### Users Schema
| Current (SQL) | Target (C#/PostgreSQL) | Entity Class |
|--------------|------------------------|--------------|
| `"Users"` | `users` | `User` |
| `"Permissions"` | `permissions` | `Permission` |
| `"Preferences"` | `preferences` | `Preference` |
| `"AccessSchedules"` | `access_schedules` | `AccessSchedule` |
### Library Schema
| Current (SQL) | Target (C#/PostgreSQL) | Entity Class |
|--------------|------------------------|--------------|
| `"BaseItems"` | `base_items` | `BaseItemEntity` |
| `"Chapters"` | `chapters` | `Chapter` |
| `"MediaStreamInfos"` | `media_stream_infos` | `MediaStreamInfo` |
| `"AttachmentStreamInfos"` | `attachment_stream_infos` | `AttachmentStreamInfo` |
| `"ImageInfos"` | `image_infos` | `ImageInfo` |
| `"BaseItemImageInfos"` | `base_item_image_infos` | `BaseItemImageInfo` |
| `"BaseItemProviders"` | `base_item_providers` | `BaseItemProvider` |
| `"BaseItemMetadataFields"` | `base_item_metadata_fields` | `BaseItemMetadataField` |
| `"BaseItemTrailerTypes"` | `base_item_trailer_types` | `BaseItemTrailerType` |
| `"ItemValues"` | `item_values` | `ItemValue` |
| `"ItemValuesMaps"` | `item_values_map` | `ItemValueMap` |
| `"Peoples"` | `peoples` | `People` |
| `"PeopleBaseItemMaps"` | `people_base_item_map` | `PeopleBaseItemMap` |
| `"UserData"` | `user_data` | `UserData` |
| `"AncestorIds"` | `ancestor_ids` | `AncestorId` |
| `"TrickplayInfos"` | `trickplay_infos` | `TrickplayInfo` |
| `"MediaSegments"` | `media_segments` | `MediaSegment` |
| `"KeyframeData"` | `keyframe_data` | `KeyframeData` |
| `"LibraryOptions"` | `library_options` | `LibraryOptionsEntity` |
### Special Tables
| Current (SQL) | Target (C#/PostgreSQL) | Notes |
|--------------|------------------------|-------|
| `"__EFMigrationsHistory"` | `__ef_migrations_history` | System table, special handling |
### Views (Library Schema)
| Current (SQL) | Target (C#/PostgreSQL) | Entity Class |
|--------------|------------------------|--------------|
| `"media_stream_infos_v"` | `media_stream_infos_v` | `MediaStreamInfoView` (already lowercase) |
| `"video_items_v"` | `video_items_v` | `VideoItemView` (already lowercase) |
| `"user_playback_history_v"` | `user_playback_history_v` | `UserPlaybackHistoryView` (already lowercase) |
| `"item_providers_v"` | `item_providers_v` | `ItemProviderView` (already lowercase) |
| `"item_people_v"` | `item_people_v` | `ItemPersonView` (already lowercase) |
| `"library_summary_v"` | `library_summary_v` | `LibrarySummaryView` (already lowercase) |
---
## Column Naming Rules
### SnakeCaseNamingConvention Conversion Rules
```csharp
// From SnakeCaseNamingConvention.cs - regex patterns applied:
// Rule 1: ([A-Z]+)([A-Z][a-z]) → "$1_$2" // Consecutive capitals: HTTPServer → HTTP_Server
// Rule 2: ([a-z\d])([A-Z]) → "$1_$2" // Lowercase/digit to capital: dateCreated → date_Created
// Rule 3: .ToLowerInvariant() // Lowercase: date_Created → date_created
```
### Common Column Conversions
Single-Word Columns:
- `"Id"``id`
- `"Name"``name`
- `"Type"``type`
- `"UserId"``user_id`
- `"ItemId"``item_id`
Multi-Word Columns:
- `"DateCreated"``date_created`
- `"DateModified"``date_modified`
- `"DateLastActivity"``date_last_activity`
- `"AccessToken"``access_token`
- `"IsMovie"``is_movie`
- `"IsSeries"``is_series`
- `"ShortOverview"``short_overview`
- `"LogSeverity"``log_severity`
- `"RowVersion"``row_version`
- `"DisplayOrder"``display_order`
- `"BaseItemId"``base_item_id`
- `"DeviceId"``device_id`
- `"ProviderId"``provider_id`
- `"SortName"``sort_name`
- `"ProviderIds"``provider_ids`
- `"DvVersionMajor"``dv_version_major`
- `"DvVersionMinor"``dv_version_minor`
- `"DvProfile"``dv_profile`
- `"DvLevel"``dv_level`
- `"RpuVersion"``rpu_version`
- `"CodecTag"``codec_tag`
- `"IsHDR"``is_hdr`
- `"IsHDR10"``is_hdr10`
- `"SeriesPresentationUniqueKey"``series_presentation_unique_key`
---
## Conversion Strategy in create_database_schema.sql
### Phase 1: Table Definition Lines
Find and replace quoted PascalCase table names immediately after `CREATE TABLE`:
- `CREATE TABLE activitylog."ActivityLogs"``CREATE TABLE activitylog.activity_logs`
- `CREATE TABLE authentication."ApiKeys"``CREATE TABLE authentication.api_keys`
- etc. (all 19 tables in schema sections)
### Phase 2: Column Definitions
Within each `CREATE TABLE` block, replace all quoted column names:
- `"Id"``id`
- `"Name"``name`
- `"DateCreated"``date_created`
- etc. (200+ column replacements across all tables)
### Phase 3: Sequence Names
Update sequence definitions to match renamed tables:
- `SEQUENCE NAME activitylog."ActivityLogs_Id_seq"``SEQUENCE NAME activitylog.activity_logs_id_seq`
- etc.
### Phase 4: Constraint References
Update all foreign key and constraint definitions:
- `CONSTRAINT "fk_base_items_users_user_id" FOREIGN KEY ("BaseItemId") REFERENCES users."Users" ("Id")`
`CONSTRAINT fk_base_items_users_user_id FOREIGN KEY (base_item_id) REFERENCES users.users (id)`
### Phase 5: Index References
Update index definitions:
- `CREATE INDEX "idx_activity_logs_user_id" ON activitylog."ActivityLogs" ("UserId")`
`CREATE INDEX idx_activity_logs_user_id ON activitylog.activity_logs (user_id)`
### Phase 6: Special Table (__EFMigrationsHistory)
Update system table for consistency:
- `"__EFMigrationsHistory"``__ef_migrations_history`
- All its columns follow the same snake_case rule
---
## File Location
- **Source**: `Jellyfin.Server/sql/schema_init/create_database_schema.sql` (1879 lines)
- **Output**: Same file (in-place conversion)
---
## Validation Checklist
- [ ] All 19 application tables converted from PascalCase to snake_case
- [ ] All 200+ columns converted to lowercase/snake_case
- [ ] All sequence names updated
- [ ] All foreign key references updated
- [ ] All indexes updated
- [ ] Special table `__ef_migrations_history` created with lowercase columns
- [ ] Views remain unchanged (already lowercase)
- [ ] SQL syntax is valid
- [ ] No orphaned quotes remain in identifier positions
- [ ] Schema still respects owner = jellyfin
---
Generated: 2025-05-01
Reference Documents:
- `PostgresDatabaseProvider.cs` lines 763-875
- `SnakeCaseNamingConvention.cs` lines 16-40
- `create_database_schema.sql` full schema dump