Add automatic PostgreSQL database creation and migration
- Added Jellyfin.Database.Providers.Postgres project with full EF Core migration support for PostgreSQL. - Implemented automatic database creation and privilege assignment on startup. - Generated initial migration and model snapshot for PostgreSQL schema. - Updated build, test, and dependency files to include PostgreSQL provider and Npgsql packages. - Added PowerShell script for generating and testing PostgreSQL migrations. - No changes to application logic outside database provider/migration infrastructure.
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
# Database Schema Creation - How It Works
|
||||
|
||||
## Yes! The Database Schema is Created Automatically
|
||||
|
||||
Jellyfin has a sophisticated migration system that **automatically creates all database tables** when you first run it with a new database provider.
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. **First-Time Initialization** (New Installation)
|
||||
|
||||
When Jellyfin starts for the first time:
|
||||
|
||||
```csharp
|
||||
// From JellyfinMigrationService.cs lines 113-118
|
||||
var databaseCreator = dbContext.Database.GetService<IDatabaseCreator>() as IRelationalDatabaseCreator;
|
||||
if (!await databaseCreator.ExistsAsync().ConfigureAwait(false))
|
||||
{
|
||||
await databaseCreator.CreateAsync().ConfigureAwait(false);
|
||||
}
|
||||
```
|
||||
|
||||
**What happens:**
|
||||
1. Checks if database exists
|
||||
2. If not, **creates the database**
|
||||
3. Creates the `__EFMigrationsHistory` table to track applied migrations
|
||||
4. Seeds initial migration records
|
||||
|
||||
### 2. **Migration Application**
|
||||
|
||||
The `JellyfinMigrationService` manages two types of migrations:
|
||||
|
||||
#### A. **Database Migrations** (EF Core Schema Migrations)
|
||||
These create the actual tables, columns, indexes, and constraints.
|
||||
|
||||
**SQLite**: Has 75+ migration files (as of current version)
|
||||
- Located in: `src\Jellyfin.Database\Jellyfin.Database.Providers.Sqlite\Migrations\`
|
||||
- Examples:
|
||||
- `20200514181226_AddActivityLog.cs`
|
||||
- `20200613202153_AddUsers.cs`
|
||||
- `20241020103111_LibraryDbMigration.cs`
|
||||
|
||||
**PostgreSQL**: Currently has **NO migration files yet** ⚠️
|
||||
|
||||
#### B. **Code Migrations** (Data Migrations)
|
||||
These handle data transformations and post-schema setup tasks.
|
||||
|
||||
```csharp
|
||||
// From JellyfinMigrationService.cs lines 459-460
|
||||
var migrator = _jellyfinDbContext.GetService<IMigrator>();
|
||||
await migrator.MigrateAsync(_databaseMigrationInfo.Key).ConfigureAwait(false);
|
||||
```
|
||||
|
||||
### 3. **Migration Stages**
|
||||
|
||||
Migrations run in specific stages during startup:
|
||||
|
||||
```csharp
|
||||
public enum JellyfinMigrationStageTypes
|
||||
{
|
||||
PreStartup,
|
||||
CoreInitialisation, // <- Database schema created here
|
||||
PostStartup
|
||||
}
|
||||
```
|
||||
|
||||
**CoreInitialisation Stage** is where:
|
||||
- EF Core migrations are applied
|
||||
- Database schema (tables) is created
|
||||
- Indexes and constraints are added
|
||||
|
||||
## Current PostgreSQL Status
|
||||
|
||||
### ⚠️ **Important**: PostgreSQL Migrations Need to Be Generated
|
||||
|
||||
The PostgreSQL provider is **missing EF Core migration files**. This means:
|
||||
|
||||
❌ **What's Missing:**
|
||||
- No `.cs` migration files in `src\Jellyfin.Database\Jellyfin.Database.Providers.Postgres\Migrations\`
|
||||
- Schema won't be created automatically for PostgreSQL
|
||||
- First run will fail or create empty database
|
||||
|
||||
✅ **What Exists:**
|
||||
- `PostgresDesignTimeJellyfinDbFactory.cs` - Design-time factory for generating migrations
|
||||
- PostgreSQL provider implementation
|
||||
- Connection and configuration code
|
||||
|
||||
### How to Generate PostgreSQL Migrations
|
||||
|
||||
You need to generate the initial migration that creates all tables:
|
||||
|
||||
```bash
|
||||
# Navigate to the PostgreSQL provider project
|
||||
cd src\Jellyfin.Database\Jellyfin.Database.Providers.Postgres
|
||||
|
||||
# Generate initial migration (creates all tables)
|
||||
dotnet ef migrations add InitialCreate --context JellyfinDbContext --output-dir Migrations
|
||||
|
||||
# Or, copy and adapt migrations from SQLite provider
|
||||
# This is more complex but ensures parity with SQLite schema
|
||||
```
|
||||
|
||||
### Alternative: Runtime Schema Creation (Development Only)
|
||||
|
||||
For development/testing, you could modify the code to use `EnsureCreated()`:
|
||||
|
||||
```csharp
|
||||
// WARNING: Only for development - bypasses migration system
|
||||
await dbContext.Database.EnsureCreatedAsync().ConfigureAwait(false);
|
||||
```
|
||||
|
||||
⚠️ **Don't use in production** - this bypasses the migration history system.
|
||||
|
||||
## What Gets Created
|
||||
|
||||
When migrations run properly, they create these tables:
|
||||
|
||||
### Core Tables (from JellyfinDbContext.cs)
|
||||
- **Users** - User accounts
|
||||
- **Permissions** - User permissions
|
||||
- **Preferences** - User preferences
|
||||
- **AccessSchedules** - Access time restrictions
|
||||
- **ActivityLogs** - Activity/audit logs
|
||||
- **ApiKeys** - API authentication keys
|
||||
- **Devices** - Client devices
|
||||
- **DeviceOptions** - Device-specific settings
|
||||
- **DisplayPreferences** - UI display settings
|
||||
- **ItemDisplayPreferences** - Item-specific display settings
|
||||
- **CustomItemDisplayPreferences** - Custom item preferences
|
||||
- **ImageInfos** - Image metadata
|
||||
- **TrickplayInfos** - Video preview thumbnails metadata
|
||||
- **MediaSegments** - Video chapter/intro/credits data
|
||||
|
||||
### Library Tables (from BaseItemRepository)
|
||||
- **BaseItems** - Media library items (movies, shows, etc.)
|
||||
- **AncestorIds** - Item hierarchy relationships
|
||||
- **AttachmentStreamInfos** - Subtitle/attachment metadata
|
||||
- **Chapters** - Video chapter information
|
||||
- **ItemValues** - Genre/Studio/Artist tags
|
||||
- **ItemValuesMap** - Tag-to-item relationships
|
||||
- **MediaStreamInfos** - Audio/video stream metadata
|
||||
- **UserData** - Watch history, ratings, favorites
|
||||
|
||||
### System Tables
|
||||
- **__EFMigrationsHistory** - Tracks applied migrations
|
||||
|
||||
## Verifying Schema Creation
|
||||
|
||||
### After Jellyfin Starts Successfully
|
||||
|
||||
**SQLite:**
|
||||
```bash
|
||||
sqlite3 data/jellyfin.db ".tables"
|
||||
```
|
||||
|
||||
**PostgreSQL:**
|
||||
```bash
|
||||
psql -U jellyfin -d jellyfin -c "\dt"
|
||||
```
|
||||
|
||||
You should see all the tables listed above.
|
||||
|
||||
### Checking Migration History
|
||||
|
||||
**PostgreSQL:**
|
||||
```sql
|
||||
SELECT * FROM "__EFMigrationsHistory" ORDER BY "MigrationId";
|
||||
```
|
||||
|
||||
This shows which migrations have been applied.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: "Table does not exist"
|
||||
|
||||
**Cause:** Migrations haven't been applied
|
||||
|
||||
**Solution:**
|
||||
1. Check logs for migration errors
|
||||
2. Verify database connection
|
||||
3. Ensure migrations exist in the provider assembly
|
||||
4. Manually run: `dotnet ef database update`
|
||||
|
||||
### PostgreSQL: No Tables Created
|
||||
|
||||
**Cause:** PostgreSQL provider has no migration files
|
||||
|
||||
**Solution:** Generate migrations:
|
||||
```bash
|
||||
cd src\Jellyfin.Database\Jellyfin.Database.Providers.Postgres
|
||||
dotnet ef migrations add InitialCreate --context JellyfinDbContext
|
||||
```
|
||||
|
||||
### Migration Fails
|
||||
|
||||
**Cause:** Database permissions, connection issues, or corrupt migration
|
||||
|
||||
**Solution:**
|
||||
1. Check database user has CREATE TABLE permissions
|
||||
2. Verify connection string
|
||||
3. Check logs: `<config-dir>/logs/`
|
||||
4. Restore from backup if available
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Development
|
||||
1. **Keep migrations in sync** between providers
|
||||
2. **Test migrations** before deploying
|
||||
3. **Backup database** before applying migrations
|
||||
4. **Use source control** for migration files
|
||||
|
||||
### For Production
|
||||
1. **Never use EnsureCreated()** - always use migrations
|
||||
2. **Backup before upgrades** that include migrations
|
||||
3. **Test migrations** in staging environment first
|
||||
4. **Monitor logs** during first startup with new database
|
||||
|
||||
### For Contributors
|
||||
If adding new tables/columns:
|
||||
1. **Update `JellyfinDbContext`** with new DbSets
|
||||
2. **Generate migrations** for ALL providers (SQLite, PostgreSQL)
|
||||
3. **Test migration** on clean database
|
||||
4. **Include migration** in pull request
|
||||
|
||||
## Migration Workflow
|
||||
|
||||
```
|
||||
Startup → Check Database Exists → Create if Missing
|
||||
↓
|
||||
Load Migration History
|
||||
↓
|
||||
Find Pending Migrations (compare applied vs available)
|
||||
↓
|
||||
Apply Each Migration in Order:
|
||||
- Database Migrations (schema changes)
|
||||
- Code Migrations (data transformations)
|
||||
↓
|
||||
Update Migration History
|
||||
↓
|
||||
Continue Jellyfin Startup
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
**Question:** Is there code to create the database and tables?
|
||||
|
||||
**Answer:** **YES!**
|
||||
|
||||
- ✅ Database creation: Automatic via `IDatabaseCreator`
|
||||
- ✅ Table schema: Via EF Core migrations
|
||||
- ✅ Migration tracking: Via `__EFMigrationsHistory`
|
||||
- ✅ Automatic application: Via `JellyfinMigrationService`
|
||||
- ⚠️ PostgreSQL: **Requires migration files to be generated first**
|
||||
|
||||
The system is fully automatic **once migrations exist** for your database provider. SQLite is ready to go. PostgreSQL needs its migrations generated using the `dotnet ef migrations add` command.
|
||||
Reference in New Issue
Block a user