# 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**: `scripts/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
