Delete SQlite

This commit is contained in:
Zoe Roux 2023-03-16 01:49:48 +09:00
parent e12ac9b3a4
commit 201892ea7f
39 changed files with 57 additions and 4726 deletions

View File

@ -1,7 +1,13 @@
TVDB__APIKEY=
THEMOVIEDB__APIKEY=
AUTHENTICATION_SECRET=
POSTGRES_USER=kyoousername
POSTGRES_PASSWORD=kyoopassword
POSTGRES_DB=kyooDB
PUBLIC_BACK_URL=http://localhost:5000
# Database things (optional)
POSTGRES_USER=KyooUser
POSTGRES_PASSWORD=KyooPassword
POSTGRES_DB=kyooDB
POSTGRES_SERVER=postgres
POSTGRES_PORT=5432
# vi: ft=sh

View File

@ -3,14 +3,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kyoo.Core", "src\Kyoo.Core\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Abstractions", "src\Kyoo.Abstractions\Kyoo.Abstractions.csproj", "{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Database", "src\Kyoo.Database\Kyoo.Database.csproj", "{6F91B645-F785-46BB-9C4F-1EFC83E489B6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Postgresql", "src\Kyoo.Postgresql\Kyoo.Postgresql.csproj", "{3213C96D-0BF3-460B-A8B5-B9977229408A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "src\Kyoo.Authentication\Kyoo.Authentication.csproj", "{7A841335-6523-47DB-9717-80AA7BD943FD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.SqLite", "src\Kyoo.SqLite\Kyoo.SqLite.csproj", "{6515380E-1E57-42DA-B6E3-E1C8A848818A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheTvdb", "src\Kyoo.TheTvdb\Kyoo.TheTvdb.csproj", "{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheMovieDb", "src\Kyoo.TheMovieDb\Kyoo.TheMovieDb.csproj", "{BAB270D4-E0EA-4329-BA65-512FDAB01001}"
@ -45,10 +41,6 @@ Global
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.Build.0 = Release|Any CPU
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F91B645-F785-46BB-9C4F-1EFC83E489B6}.Release|Any CPU.Build.0 = Release|Any CPU
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -98,7 +90,6 @@ Global
{0C8AA7EA-E723-4532-852F-35AA4E8AFED5} = {FEAE1B0E-D797-470F-9030-0EF743575ECC}
{BAB270D4-E0EA-4329-BA65-512FDAB01001} = {8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C} = {8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}
{6F91B645-F785-46BB-9C4F-1EFC83E489B6} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
{3213C96D-0BF3-460B-A8B5-B9977229408A} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
{6515380E-1E57-42DA-B6E3-E1C8A848818A} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5} = {C569FF25-7E01-484C-9F72-5B99845AD94B}

View File

@ -1,60 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System.Diagnostics.CodeAnalysis;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A permission validator that always validate permissions. This effectively disable the permission system.
/// </summary>
public class PassthroughPermissionValidator : IPermissionValidator
{
/// <summary>
/// Create a new <see cref="PassthroughPermissionValidator"/>.
/// </summary>
/// <param name="logger">The logger used to warn that no real permission validator exists.</param>
[SuppressMessage("ReSharper", "SuggestBaseTypeForParameterInConstructor",
Justification = "ILogger should include the typeparam for context.")]
public PassthroughPermissionValidator(ILogger<PassthroughPermissionValidator> logger)
{
logger.LogWarning("No permission validator has been enabled, all users will have all permissions");
}
/// <inheritdoc />
public IFilterMetadata Create(PermissionAttribute attribute)
{
return new PassthroughValidator();
}
/// <inheritdoc />
public IFilterMetadata Create(PartialPermissionAttribute attribute)
{
return new PassthroughValidator();
}
/// <summary>
/// An useless filter that does nothing.
/// </summary>
private class PassthroughValidator : IFilterMetadata { }
}
}

View File

@ -22,7 +22,7 @@ using System.Linq;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers

View File

@ -23,7 +23,7 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Kyoo.Postgresql;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;

View File

@ -19,11 +19,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers

View File

@ -24,7 +24,7 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers

View File

@ -19,11 +19,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Postgresql;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;

View File

@ -23,8 +23,7 @@ using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Kyoo.Postgresql;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;

View File

@ -23,7 +23,7 @@ using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers

View File

@ -19,12 +19,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers

View File

@ -16,14 +16,12 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Postgresql;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;

View File

@ -19,11 +19,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers

View File

@ -21,7 +21,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers

View File

@ -19,11 +19,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers

View File

@ -20,15 +20,12 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Autofac.Core;
using Autofac.Core.Registration;
using Kyoo.Abstractions;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Utils;
using Kyoo.Core.Controllers;
using Kyoo.Core.Models.Options;
using Kyoo.Core.Tasks;
using Kyoo.Database;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
@ -85,24 +82,18 @@ namespace Kyoo.Core
builder.RegisterTask<MetadataProviderLoader>();
builder.RegisterTask<LibraryCreator>();
static bool DatabaseIsPresent(IComponentRegistryBuilder x)
=> x.IsRegistered(new TypedService(typeof(DatabaseContext)));
builder.RegisterRepository<ILibraryRepository, LibraryRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<ILibraryItemRepository, LibraryItemRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<ICollectionRepository, CollectionRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<IShowRepository, ShowRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<ISeasonRepository, SeasonRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<IEpisodeRepository, EpisodeRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<ITrackRepository, TrackRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<IPeopleRepository, PeopleRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<IStudioRepository, StudioRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<IGenreRepository, GenreRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<IProviderRepository, ProviderRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterRepository<IUserRepository, UserRepository>().OnlyIf(DatabaseIsPresent);
builder.RegisterType<PassthroughPermissionValidator>().As<IPermissionValidator>()
.IfNotRegistered(typeof(IPermissionValidator));
builder.RegisterRepository<ILibraryRepository, LibraryRepository>();
builder.RegisterRepository<ILibraryItemRepository, LibraryItemRepository>();
builder.RegisterRepository<ICollectionRepository, CollectionRepository>();
builder.RegisterRepository<IShowRepository, ShowRepository>();
builder.RegisterRepository<ISeasonRepository, SeasonRepository>();
builder.RegisterRepository<IEpisodeRepository, EpisodeRepository>();
builder.RegisterRepository<ITrackRepository, TrackRepository>();
builder.RegisterRepository<IPeopleRepository, PeopleRepository>();
builder.RegisterRepository<IStudioRepository, StudioRepository>();
builder.RegisterRepository<IGenreRepository, GenreRepository>();
builder.RegisterRepository<IProviderRepository, ProviderRepository>();
builder.RegisterRepository<IUserRepository, UserRepository>();
builder.RegisterType<FileExtensionContentTypeProvider>().As<IContentTypeProvider>().SingleInstance()
.OnActivating(x =>

View File

@ -19,7 +19,7 @@
<ItemGroup>
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
<ProjectReference Include="../Kyoo.Database/Kyoo.Database.csproj" />
<ProjectReference Include="..\Kyoo.Postgresql\Kyoo.Postgresql.csproj" />
</ItemGroup>
<Target Name="BuildTranscoder" BeforeTargets="BeforeBuild" Condition="'$(SkipTranscoder)' != 'true' And !Exists('$(TranscoderRoot)/build/$(TranscoderBinary)')">

View File

@ -1,65 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System.Data.Common;
using Microsoft.Extensions.Configuration;
namespace Kyoo.Database
{
/// <summary>
/// A class that regroup extensions used by some asp-net related parts of the app.
/// </summary>
public static class Extensions
{
/// <summary>
/// Get a connection string from the Configuration's section "Database"
/// </summary>
/// <param name="config">The IConfiguration instance to use.</param>
/// <param name="database">The database's name.</param>
/// <returns>A parsed connection string</returns>
public static string GetDatabaseConnection(this IConfiguration config, string database)
{
static string ToDbProperty(string key)
{
return key.ToUpperInvariant() switch
{
"USER" => "USER ID",
_ => key
};
}
DbConnectionStringBuilder builder = new();
IConfigurationSection section = config.GetSection("database:configurations").GetSection(database);
foreach (IConfigurationSection child in section.GetChildren())
{
builder[ToDbProperty(child.Key)] = child.Value;
}
return builder.ConnectionString;
}
/// <summary>
/// Get the name of the selected database.
/// </summary>
/// <param name="config">The IConfiguration instance to use.</param>
/// <returns>The name of the selected database.</returns>
public static string GetSelectedDatabase(this IConfiguration config)
{
return config.GetValue<string>("database:enabled");
}
}
}

View File

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Kyoo.Database</AssemblyName>
<RootNamespace>Kyoo.Database</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@ -17,7 +17,6 @@
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
@ -32,7 +31,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Hosting.Systemd;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using Serilog;
using Serilog.Templates;
using Serilog.Templates.Themes;

View File

@ -27,7 +27,6 @@ using Kyoo.Core;
using Kyoo.Core.Models.Options;
using Kyoo.Host.Generic.Controllers;
using Kyoo.Postgresql;
using Kyoo.SqLite;
using Kyoo.Swagger;
using Kyoo.TheMovieDb;
using Kyoo.TheTvdb;
@ -78,7 +77,6 @@ namespace Kyoo.Host.Generic
typeof(CoreModule),
typeof(AuthenticationModule),
typeof(PostgresModule),
typeof(SqLiteModule),
typeof(PluginTvdb),
typeof(PluginTmdb),
typeof(SwaggerModule)

View File

@ -7,26 +7,6 @@
"metadataPath": "metadata/"
},
"database": {
"enabled": "sqlite",
"configurations": {
"sqlite": {
"data Source": "kyoo.db",
"cache": "Shared"
},
"postgres": {
"server": "127.0.0.1",
"port": "5432",
"database": "kyooDB",
"user": "kyoo",
"password": "kyooPassword",
"pooling": "true",
"maxPoolSize": "95",
"timeout": "30"
}
}
},
"logging": {
"MinimumLevel": {
"Default": "Warning",

View File

@ -29,7 +29,7 @@ using Kyoo.Abstractions.Models.Exceptions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace Kyoo.Database
namespace Kyoo.Postgresql
{
/// <summary>
/// The database handle used for all local repositories.

View File

@ -11,10 +11,10 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.8" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Kyoo.Database\Kyoo.Database.csproj" />
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@ -22,7 +22,6 @@ using System.Linq.Expressions;
using System.Reflection;
using EFCore.NamingConventions.Internal;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;
using Npgsql;

View File

@ -18,8 +18,8 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using Kyoo.Abstractions.Controllers;
using Kyoo.Database;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
@ -47,7 +47,7 @@ namespace Kyoo.Postgresql
public Dictionary<string, Type> Configuration => new();
/// <inheritdoc />
public bool Enabled => _configuration.GetSelectedDatabase() == "postgres";
public bool Enabled => true;
/// <summary>
/// The configuration to use. The database connection string is pulled from it.
@ -75,7 +75,18 @@ namespace Kyoo.Postgresql
{
services.AddDbContext<DatabaseContext, PostgresContext>(x =>
{
x.UseNpgsql(_configuration.GetDatabaseConnection("postgres"));
DbConnectionStringBuilder builder = new()
{
["USER ID"] = _configuration.GetValue("POSTGRES_USER", "KyooUser"),
["PASSWORD"] = _configuration.GetValue("POSTGRES_PASSWORD", "KyooPassword"),
["SERVER"] = _configuration.GetValue("POSTGRES_SERVER", "db"),
["PORT"] = _configuration.GetValue("POSTGRES_PORT", "5432"),
["DATABASE"] = _configuration.GetValue("POSTGRES_DB", "kyooDB"),
["POOLING"] = "true",
["MAXPOOLSIZE"] = "95",
["TIMEOUT"] = "30"
};
x.UseNpgsql(builder.ConnectionString);
if (_environment.IsDevelopment())
x.EnableDetailedErrors().EnableSensitiveDataLogging();
}, ServiceLifetime.Transient);

View File

@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Kyoo.SqLite</AssemblyName>
<RootNamespace>Kyoo.SqLite</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.8" />
<ProjectReference Include="../Kyoo.Database/Kyoo.Database.csproj" />
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -1,861 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Kyoo.SqLite.Migrations
{
/// <summary>
/// The initial migration that build most of the database.
/// </summary>
public partial class Initial : Migration
{
/// <inheritdoc/>
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Collections",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true),
Overview = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Collections", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Genres",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Genres", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Libraries",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true),
Paths = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Libraries", x => x.ID);
});
migrationBuilder.CreateTable(
name: "People",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_People", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Providers",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Providers", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Studios",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Studios", x => x.ID);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Username = table.Column<string>(type: "TEXT", nullable: true),
Email = table.Column<string>(type: "TEXT", nullable: true),
Password = table.Column<string>(type: "TEXT", nullable: true),
Permissions = table.Column<string>(type: "TEXT", nullable: true),
ExtraData = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.ID);
});
migrationBuilder.CreateTable(
name: "LinkLibraryCollection",
columns: table => new
{
CollectionID = table.Column<int>(type: "INTEGER", nullable: false),
LibraryID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkLibraryCollection", x => new { x.CollectionID, x.LibraryID });
table.ForeignKey(
name: "FK_LinkLibraryCollection_Collections_CollectionID",
column: x => x.CollectionID,
principalTable: "Collections",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkLibraryCollection_Libraries_LibraryID",
column: x => x.LibraryID,
principalTable: "Libraries",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "CollectionMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CollectionMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_CollectionMetadataID_Collections_ResourceID",
column: x => x.ResourceID,
principalTable: "Collections",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_CollectionMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkLibraryProvider",
columns: table => new
{
LibraryID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkLibraryProvider", x => new { x.LibraryID, x.ProviderID });
table.ForeignKey(
name: "FK_LinkLibraryProvider_Libraries_LibraryID",
column: x => x.LibraryID,
principalTable: "Libraries",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkLibraryProvider_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "PeopleMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PeopleMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_PeopleMetadataID_People_ResourceID",
column: x => x.ResourceID,
principalTable: "People",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_PeopleMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Shows",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: false),
Title = table.Column<string>(type: "TEXT", nullable: true),
Aliases = table.Column<string>(type: "TEXT", nullable: true),
Path = table.Column<string>(type: "TEXT", nullable: true),
Overview = table.Column<string>(type: "TEXT", nullable: true),
Status = table.Column<int>(type: "INTEGER", nullable: false),
StartAir = table.Column<DateTime>(type: "TEXT", nullable: true),
EndAir = table.Column<DateTime>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true),
IsMovie = table.Column<bool>(type: "INTEGER", nullable: false),
StudioID = table.Column<int>(type: "INTEGER", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Shows", x => x.ID);
table.ForeignKey(
name: "FK_Shows_Studios_StudioID",
column: x => x.StudioID,
principalTable: "Studios",
principalColumn: "ID",
onDelete: ReferentialAction.SetNull);
});
migrationBuilder.CreateTable(
name: "StudioMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_StudioMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_StudioMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_StudioMetadataID_Studios_ResourceID",
column: x => x.ResourceID,
principalTable: "Studios",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkCollectionShow",
columns: table => new
{
CollectionID = table.Column<int>(type: "INTEGER", nullable: false),
ShowID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkCollectionShow", x => new { x.CollectionID, x.ShowID });
table.ForeignKey(
name: "FK_LinkCollectionShow_Collections_CollectionID",
column: x => x.CollectionID,
principalTable: "Collections",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkCollectionShow_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkLibraryShow",
columns: table => new
{
LibraryID = table.Column<int>(type: "INTEGER", nullable: false),
ShowID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkLibraryShow", x => new { x.LibraryID, x.ShowID });
table.ForeignKey(
name: "FK_LinkLibraryShow_Libraries_LibraryID",
column: x => x.LibraryID,
principalTable: "Libraries",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkLibraryShow_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkShowGenre",
columns: table => new
{
GenreID = table.Column<int>(type: "INTEGER", nullable: false),
ShowID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkShowGenre", x => new { x.GenreID, x.ShowID });
table.ForeignKey(
name: "FK_LinkShowGenre_Genres_GenreID",
column: x => x.GenreID,
principalTable: "Genres",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkShowGenre_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "LinkUserShow",
columns: table => new
{
UsersID = table.Column<int>(type: "INTEGER", nullable: false),
WatchedID = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LinkUserShow", x => new { x.UsersID, x.WatchedID });
table.ForeignKey(
name: "FK_LinkUserShow_Shows_WatchedID",
column: x => x.WatchedID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_LinkUserShow_Users_UsersID",
column: x => x.UsersID,
principalTable: "Users",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "PeopleRoles",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
PeopleID = table.Column<int>(type: "INTEGER", nullable: false),
ShowID = table.Column<int>(type: "INTEGER", nullable: false),
Type = table.Column<string>(type: "TEXT", nullable: true),
Role = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PeopleRoles", x => x.ID);
table.ForeignKey(
name: "FK_PeopleRoles_People_PeopleID",
column: x => x.PeopleID,
principalTable: "People",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_PeopleRoles_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Seasons",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: true),
ShowID = table.Column<int>(type: "INTEGER", nullable: false),
SeasonNumber = table.Column<int>(type: "INTEGER", nullable: false),
Title = table.Column<string>(type: "TEXT", nullable: true),
Overview = table.Column<string>(type: "TEXT", nullable: true),
StartDate = table.Column<DateTime>(type: "TEXT", nullable: true),
EndDate = table.Column<DateTime>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Seasons", x => x.ID);
table.ForeignKey(
name: "FK_Seasons_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ShowMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ShowMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_ShowMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ShowMetadataID_Shows_ResourceID",
column: x => x.ResourceID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Episodes",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: true),
ShowID = table.Column<int>(type: "INTEGER", nullable: false),
SeasonID = table.Column<int>(type: "INTEGER", nullable: true),
SeasonNumber = table.Column<int>(type: "INTEGER", nullable: true),
EpisodeNumber = table.Column<int>(type: "INTEGER", nullable: true),
AbsoluteNumber = table.Column<int>(type: "INTEGER", nullable: true),
Path = table.Column<string>(type: "TEXT", nullable: true),
Images = table.Column<string>(type: "TEXT", nullable: true),
Title = table.Column<string>(type: "TEXT", nullable: true),
Overview = table.Column<string>(type: "TEXT", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Episodes", x => x.ID);
table.ForeignKey(
name: "FK_Episodes_Seasons_SeasonID",
column: x => x.SeasonID,
principalTable: "Seasons",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Episodes_Shows_ShowID",
column: x => x.ShowID,
principalTable: "Shows",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "SeasonMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_SeasonMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_SeasonMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_SeasonMetadataID_Seasons_ResourceID",
column: x => x.ResourceID,
principalTable: "Seasons",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "EpisodeMetadataID",
columns: table => new
{
ResourceID = table.Column<int>(type: "INTEGER", nullable: false),
ProviderID = table.Column<int>(type: "INTEGER", nullable: false),
DataID = table.Column<string>(type: "TEXT", nullable: true),
Link = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_EpisodeMetadataID", x => new { x.ResourceID, x.ProviderID });
table.ForeignKey(
name: "FK_EpisodeMetadataID_Episodes_ResourceID",
column: x => x.ResourceID,
principalTable: "Episodes",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_EpisodeMetadataID_Providers_ProviderID",
column: x => x.ProviderID,
principalTable: "Providers",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Tracks",
columns: table => new
{
ID = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Slug = table.Column<string>(type: "TEXT", nullable: true),
Title = table.Column<string>(type: "TEXT", nullable: true),
Language = table.Column<string>(type: "TEXT", nullable: true),
Codec = table.Column<string>(type: "TEXT", nullable: true),
IsDefault = table.Column<bool>(type: "INTEGER", nullable: false),
IsForced = table.Column<bool>(type: "INTEGER", nullable: false),
IsExternal = table.Column<bool>(type: "INTEGER", nullable: false),
Path = table.Column<string>(type: "TEXT", nullable: true),
Type = table.Column<int>(type: "INTEGER", nullable: false),
EpisodeID = table.Column<int>(type: "INTEGER", nullable: false),
TrackIndex = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Tracks", x => x.ID);
table.ForeignKey(
name: "FK_Tracks_Episodes_EpisodeID",
column: x => x.EpisodeID,
principalTable: "Episodes",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "WatchedEpisodes",
columns: table => new
{
UserID = table.Column<int>(type: "INTEGER", nullable: false),
EpisodeID = table.Column<int>(type: "INTEGER", nullable: false),
WatchedPercentage = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_WatchedEpisodes", x => new { x.UserID, x.EpisodeID });
table.ForeignKey(
name: "FK_WatchedEpisodes_Episodes_EpisodeID",
column: x => x.EpisodeID,
principalTable: "Episodes",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_WatchedEpisodes_Users_UserID",
column: x => x.UserID,
principalTable: "Users",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_CollectionMetadataID_ProviderID",
table: "CollectionMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Collections_Slug",
table: "Collections",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_EpisodeMetadataID_ProviderID",
table: "EpisodeMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Episodes_SeasonID",
table: "Episodes",
column: "SeasonID");
migrationBuilder.CreateIndex(
name: "IX_Episodes_ShowID_SeasonNumber_EpisodeNumber_AbsoluteNumber",
table: "Episodes",
columns: new[] { "ShowID", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Episodes_Slug",
table: "Episodes",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Genres_Slug",
table: "Genres",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Libraries_Slug",
table: "Libraries",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_LinkCollectionShow_ShowID",
table: "LinkCollectionShow",
column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_LinkLibraryCollection_LibraryID",
table: "LinkLibraryCollection",
column: "LibraryID");
migrationBuilder.CreateIndex(
name: "IX_LinkLibraryProvider_ProviderID",
table: "LinkLibraryProvider",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_LinkLibraryShow_ShowID",
table: "LinkLibraryShow",
column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_LinkShowGenre_ShowID",
table: "LinkShowGenre",
column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_LinkUserShow_WatchedID",
table: "LinkUserShow",
column: "WatchedID");
migrationBuilder.CreateIndex(
name: "IX_People_Slug",
table: "People",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_PeopleMetadataID_ProviderID",
table: "PeopleMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_PeopleRoles_PeopleID",
table: "PeopleRoles",
column: "PeopleID");
migrationBuilder.CreateIndex(
name: "IX_PeopleRoles_ShowID",
table: "PeopleRoles",
column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_Providers_Slug",
table: "Providers",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_SeasonMetadataID_ProviderID",
table: "SeasonMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Seasons_ShowID_SeasonNumber",
table: "Seasons",
columns: new[] { "ShowID", "SeasonNumber" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Seasons_Slug",
table: "Seasons",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_ShowMetadataID_ProviderID",
table: "ShowMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Shows_Slug",
table: "Shows",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Shows_StudioID",
table: "Shows",
column: "StudioID");
migrationBuilder.CreateIndex(
name: "IX_StudioMetadataID_ProviderID",
table: "StudioMetadataID",
column: "ProviderID");
migrationBuilder.CreateIndex(
name: "IX_Studios_Slug",
table: "Studios",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Tracks_EpisodeID_Type_Language_TrackIndex_IsForced",
table: "Tracks",
columns: new[] { "EpisodeID", "Type", "Language", "TrackIndex", "IsForced" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Tracks_Slug",
table: "Tracks",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Users_Slug",
table: "Users",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_WatchedEpisodes_EpisodeID",
table: "WatchedEpisodes",
column: "EpisodeID");
}
/// <inheritdoc/>
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CollectionMetadataID");
migrationBuilder.DropTable(
name: "EpisodeMetadataID");
migrationBuilder.DropTable(
name: "LinkCollectionShow");
migrationBuilder.DropTable(
name: "LinkLibraryCollection");
migrationBuilder.DropTable(
name: "LinkLibraryProvider");
migrationBuilder.DropTable(
name: "LinkLibraryShow");
migrationBuilder.DropTable(
name: "LinkShowGenre");
migrationBuilder.DropTable(
name: "LinkUserShow");
migrationBuilder.DropTable(
name: "PeopleMetadataID");
migrationBuilder.DropTable(
name: "PeopleRoles");
migrationBuilder.DropTable(
name: "SeasonMetadataID");
migrationBuilder.DropTable(
name: "ShowMetadataID");
migrationBuilder.DropTable(
name: "StudioMetadataID");
migrationBuilder.DropTable(
name: "Tracks");
migrationBuilder.DropTable(
name: "WatchedEpisodes");
migrationBuilder.DropTable(
name: "Collections");
migrationBuilder.DropTable(
name: "Libraries");
migrationBuilder.DropTable(
name: "Genres");
migrationBuilder.DropTable(
name: "People");
migrationBuilder.DropTable(
name: "Providers");
migrationBuilder.DropTable(
name: "Episodes");
migrationBuilder.DropTable(
name: "Users");
migrationBuilder.DropTable(
name: "Seasons");
migrationBuilder.DropTable(
name: "Shows");
migrationBuilder.DropTable(
name: "Studios");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,208 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using Microsoft.EntityFrameworkCore.Migrations;
namespace Kyoo.SqLite.Migrations
{
/// <summary>
/// A migration that adds sqlite triggers to update slugs.
/// </summary>
public partial class Triggers : Migration
{
/// <inheritdoc/>
protected override void Up(MigrationBuilder migrationBuilder)
{
// language=SQLite
migrationBuilder.Sql(@"
CREATE TRIGGER SeasonSlugInsert AFTER INSERT ON Seasons FOR EACH ROW
BEGIN
UPDATE Seasons SET Slug = (SELECT Slug from Shows WHERE ID = ShowID) || '-s' || SeasonNumber
WHERE ID == new.ID;
END");
// language=SQLite
migrationBuilder.Sql(@"
CREATE TRIGGER SeasonSlugUpdate AFTER UPDATE OF SeasonNumber, ShowID ON Seasons FOR EACH ROW
BEGIN
UPDATE Seasons SET Slug = (SELECT Slug from Shows WHERE ID = ShowID) || '-s' || SeasonNumber
WHERE ID == new.ID;
END");
// language=SQLite
migrationBuilder.Sql(@"
CREATE TRIGGER EpisodeSlugInsert AFTER INSERT ON Episodes FOR EACH ROW
BEGIN
UPDATE Episodes
SET Slug = (SELECT Slug from Shows WHERE ID = ShowID) ||
CASE
WHEN SeasonNumber IS NULL AND AbsoluteNumber IS NULL THEN ''
WHEN SeasonNumber IS NULL THEN '-' || AbsoluteNumber
ELSE '-s' || SeasonNumber || 'e' || EpisodeNumber
END
WHERE ID == new.ID;
END");
// language=SQLite
migrationBuilder.Sql(@"
CREATE TRIGGER EpisodeSlugUpdate AFTER UPDATE OF AbsoluteNumber, EpisodeNumber, SeasonNumber, ShowID
ON Episodes FOR EACH ROW
BEGIN
UPDATE Episodes
SET Slug = (SELECT Slug from Shows WHERE ID = ShowID) ||
CASE
WHEN SeasonNumber IS NULL AND AbsoluteNumber IS NULL THEN ''
WHEN SeasonNumber IS NULL THEN '-' || AbsoluteNumber
ELSE '-s' || SeasonNumber || 'e' || EpisodeNumber
END
WHERE ID == new.ID;
END");
// language=SQLite
migrationBuilder.Sql(@"
CREATE TRIGGER TrackSlugInsert
AFTER INSERT ON Tracks
FOR EACH ROW
BEGIN
UPDATE Tracks SET TrackIndex = (
SELECT COUNT(*) FROM Tracks
WHERE EpisodeID = new.EpisodeID AND Type = new.Type
AND Language = new.Language AND IsForced = new.IsForced
) WHERE ID = new.ID AND TrackIndex = 0;
UPDATE Tracks SET Slug = (SELECT Slug FROM Episodes WHERE ID = EpisodeID) ||
'.' || COALESCE(Language, 'und') ||
CASE (TrackIndex)
WHEN 0 THEN ''
ELSE '-' || (TrackIndex)
END ||
CASE (IsForced)
WHEN false THEN ''
ELSE '.forced'
END ||
CASE (Type)
WHEN 1 THEN '.video'
WHEN 2 THEN '.audio'
WHEN 3 THEN '.subtitle'
ELSE '.' || Type
END
WHERE ID = new.ID;
END;");
// language=SQLite
migrationBuilder.Sql(@"
CREATE TRIGGER TrackSlugUpdate
AFTER UPDATE OF EpisodeID, IsForced, Language, TrackIndex, Type ON Tracks
FOR EACH ROW
BEGIN
UPDATE Tracks SET TrackIndex = (
SELECT COUNT(*) FROM Tracks
WHERE EpisodeID = new.EpisodeID AND Type = new.Type
AND Language = new.Language AND IsForced = new.IsForced
) WHERE ID = new.ID AND TrackIndex = 0;
UPDATE Tracks SET Slug =
(SELECT Slug FROM Episodes WHERE ID = EpisodeID) ||
'.' || Language ||
CASE (TrackIndex)
WHEN 0 THEN ''
ELSE '-' || (TrackIndex)
END ||
CASE (IsForced)
WHEN false THEN ''
ELSE '.forced'
END ||
CASE (Type)
WHEN 1 THEN '.video'
WHEN 2 THEN '.audio'
WHEN 3 THEN '.subtitle'
ELSE '.' || Type
END
WHERE ID = new.ID;
END;");
// language=SQLite
migrationBuilder.Sql(@"
CREATE TRIGGER EpisodeUpdateTracksSlug
AFTER UPDATE OF Slug ON Episodes
FOR EACH ROW
BEGIN
UPDATE Tracks SET Slug =
NEW.Slug ||
'.' || Language ||
CASE (TrackIndex)
WHEN 0 THEN ''
ELSE '-' || TrackIndex
END ||
CASE (IsForced)
WHEN false THEN ''
ELSE '.forced'
END ||
CASE (Type)
WHEN 1 THEN '.video'
WHEN 2 THEN '.audio'
WHEN 3 THEN '.subtitle'
ELSE '.' || Type
END
WHERE EpisodeID = NEW.ID;
END;");
// language=SQLite
migrationBuilder.Sql(@"
CREATE TRIGGER ShowSlugUpdate AFTER UPDATE OF Slug ON Shows FOR EACH ROW
BEGIN
UPDATE Seasons SET Slug = new.Slug || '-s' || SeasonNumber WHERE ShowID = new.ID;
UPDATE Episodes
SET Slug = new.Slug ||
CASE
WHEN SeasonNumber IS NULL AND AbsoluteNumber IS NULL THEN ''
WHEN SeasonNumber IS NULL THEN '-' || AbsoluteNumber
ELSE '-s' || SeasonNumber || 'e' || EpisodeNumber
END
WHERE ShowID = new.ID;
END;");
// language=SQLite
migrationBuilder.Sql(@"
CREATE VIEW LibraryItems AS
SELECT s.ID, s.Slug, s.Title, s.Overview, s.Status, s.StartAir, s.EndAir, s.Images, CASE
WHEN s.IsMovie THEN 1
ELSE 0
END AS Type
FROM Shows AS s
WHERE NOT (EXISTS (
SELECT 1
FROM LinkCollectionShow AS l
INNER JOIN Collections AS c ON l.CollectionID = c.ID
WHERE s.ID = l.ShowID))
UNION ALL
SELECT -c0.ID, c0.Slug, c0.Name AS Title, c0.Overview, 0 AS Status,
NULL AS StartAir, NULL AS EndAir, c0.Images, 2 AS Type
FROM collections AS c0");
}
/// <inheritdoc/>
protected override void Down(MigrationBuilder migrationBuilder)
{
// language=SQLite
migrationBuilder.Sql("DROP TRIGGER SeasonSlugInsert;");
// language=SQLite
migrationBuilder.Sql("DROP TRIGGER SeasonSlugUpdate;");
// language=SQLite
migrationBuilder.Sql("DROP TRIGGER EpisodeSlugInsert;");
// language=SQLite
migrationBuilder.Sql("DROP TRIGGER EpisodeSlugUpdate;");
// language=SQLite
migrationBuilder.Sql("DROP TRIGGER ShowSlugUpdate;");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,201 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using Kyoo.Abstractions.Models;
using Kyoo.Database;
using Kyoo.Utils;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Newtonsoft.Json;
namespace Kyoo.SqLite
{
/// <summary>
/// A sqlite implementation of <see cref="DatabaseContext"/>.
/// </summary>
public class SqLiteContext : DatabaseContext
{
/// <summary>
/// The connection string to use.
/// </summary>
private readonly string _connection;
/// <summary>
/// Is this instance in debug mode?
/// </summary>
private readonly bool _debugMode;
/// <summary>
/// Should the configure step be skipped? This is used when the database is created via DbContextOptions.
/// </summary>
private readonly bool _skipConfigure;
/// <summary>
/// A basic constructor that set default values (query tracker behaviors, mapping enums...)
/// </summary>
public SqLiteContext()
{ }
/// <summary>
/// Create a new <see cref="SqLiteContext"/> using specific options
/// </summary>
/// <param name="options">The options to use.</param>
public SqLiteContext(DbContextOptions options)
: base(options)
{
_skipConfigure = true;
}
/// <summary>
/// A basic constructor that set default values (query tracker behaviors, mapping enums...)
/// </summary>
/// <param name="connection">The connection string to use</param>
/// <param name="debugMode">Is this instance in debug mode?</param>
public SqLiteContext(string connection, bool debugMode)
{
_connection = connection;
_debugMode = debugMode;
}
/// <summary>
/// Set connection information for this database context
/// </summary>
/// <param name="optionsBuilder">An option builder to fill.</param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!_skipConfigure)
{
if (_connection != null)
optionsBuilder.UseSqlite(_connection);
else
optionsBuilder.UseSqlite();
if (_debugMode)
optionsBuilder.EnableDetailedErrors().EnableSensitiveDataLogging();
}
base.OnConfiguring(optionsBuilder);
}
/// <summary>
/// Set database parameters to support every types of Kyoo.
/// </summary>
/// <param name="modelBuilder">The database's model builder.</param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
ValueConverter<string[], string> arrayConvertor = new(
x => string.Join(";", x),
x => x.Split(';', StringSplitOptions.None));
modelBuilder.Entity<Library>()
.Property(x => x.Paths)
.HasConversion(arrayConvertor);
modelBuilder.Entity<Show>()
.Property(x => x.Aliases)
.HasConversion(arrayConvertor);
modelBuilder.Entity<User>()
.Property(x => x.Permissions)
.HasConversion(arrayConvertor);
modelBuilder.Entity<Show>()
.Property(x => x.Status)
.HasConversion<int>();
modelBuilder.Entity<Track>()
.Property(x => x.Type)
.HasConversion<int>();
ValueConverter<Dictionary<string, string>, string> extraDataConvertor = new(
x => JsonConvert.SerializeObject(x),
x => JsonConvert.DeserializeObject<Dictionary<string, string>>(x));
modelBuilder.Entity<User>()
.Property(x => x.ExtraData)
.HasConversion(extraDataConvertor);
ValueConverter<Dictionary<int, string>, string> jsonConvertor = new(
x => JsonConvert.SerializeObject(x),
x => JsonConvert.DeserializeObject<Dictionary<int, string>>(x));
modelBuilder.Entity<LibraryItem>()
.Property(x => x.Images)
.HasConversion(jsonConvertor);
modelBuilder.Entity<Collection>()
.Property(x => x.Images)
.HasConversion(jsonConvertor);
modelBuilder.Entity<Show>()
.Property(x => x.Images)
.HasConversion(jsonConvertor);
modelBuilder.Entity<Season>()
.Property(x => x.Images)
.HasConversion(jsonConvertor);
modelBuilder.Entity<Episode>()
.Property(x => x.Images)
.HasConversion(jsonConvertor);
modelBuilder.Entity<People>()
.Property(x => x.Images)
.HasConversion(jsonConvertor);
modelBuilder.Entity<Provider>()
.Property(x => x.Images)
.HasConversion(jsonConvertor);
modelBuilder.Entity<User>()
.Property(x => x.Images)
.HasConversion(jsonConvertor);
modelBuilder.Entity<LibraryItem>()
.ToView("LibraryItems")
.HasKey(x => x.ID);
base.OnModelCreating(modelBuilder);
}
/// <inheritdoc />
protected override string MetadataName<T>()
{
return typeof(T).Name + nameof(MetadataID);
}
/// <inheritdoc />
protected override string LinkName<T, T2>()
{
return "Link" + typeof(T).Name + typeof(T2).Name;
}
/// <inheritdoc />
protected override string LinkNameFk<T>()
{
return typeof(T).Name + "ID";
}
/// <inheritdoc />
protected override bool IsDuplicateException(Exception ex)
{
return ex.InnerException
is SqliteException { SqliteExtendedErrorCode: 2067 /* SQLITE_CONSTRAINT_UNIQUE */ }
or SqliteException { SqliteExtendedErrorCode: 1555 /* SQLITE_CONSTRAINT_PRIMARYKEY */ };
}
/// <inheritdoc />
public override Expression<Func<T, bool>> Like<T>(Expression<Func<T, string>> query, string format)
{
MethodInfo iLike = MethodOfUtils.MethodOf<string, string, bool>(EF.Functions.Like);
MethodCallExpression call = Expression.Call(iLike, Expression.Constant(EF.Functions), query.Body, Expression.Constant(format));
return Expression.Lambda<Func<T, bool>>(call, query.Parameters);
}
}
}

View File

@ -1,90 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Kyoo.Abstractions.Controllers;
using Kyoo.Database;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Kyoo.SqLite
{
/// <summary>
/// A module to add sqlite capacity to the app.
/// </summary>
public class SqLiteModule : IPlugin
{
/// <inheritdoc />
public string Slug => "sqlite";
/// <inheritdoc />
public string Name => "SqLite";
/// <inheritdoc />
public string Description => "A database context for sqlite.";
/// <inheritdoc />
public Dictionary<string, Type> Configuration => new();
/// <inheritdoc />
public bool Enabled => _configuration.GetSelectedDatabase() == "sqlite";
/// <summary>
/// The configuration to use. The database connection string is pulled from it.
/// </summary>
private readonly IConfiguration _configuration;
/// <summary>
/// The host environment to check if the app is in debug mode.
/// </summary>
private readonly IWebHostEnvironment _environment;
/// <summary>
/// Create a new postgres module instance and use the given configuration and environment.
/// </summary>
/// <param name="configuration">The configuration to use</param>
/// <param name="env">The environment that will be used (if the env is in development mode, more information will be displayed on errors.</param>
public SqLiteModule(IConfiguration configuration, IWebHostEnvironment env)
{
_configuration = configuration;
_environment = env;
}
/// <inheritdoc />
public void Configure(IServiceCollection services)
{
services.AddDbContext<DatabaseContext, SqLiteContext>(x =>
{
x.UseSqlite(_configuration.GetDatabaseConnection("sqlite"));
if (_environment.IsDevelopment())
x.EnableDetailedErrors().EnableSensitiveDataLogging();
}, ServiceLifetime.Transient);
}
/// <inheritdoc />
public void Initialize(IServiceProvider provider)
{
DatabaseContext context = provider.GetRequiredService<DatabaseContext>();
context.Database.Migrate();
}
}
}

View File

@ -24,7 +24,7 @@ using Kyoo.Core.Controllers;
using Kyoo.Database;
using Xunit.Abstractions;
namespace Kyoo.Tests
namespace Kyoo.Tests.Database
{
public class RepositoryActivator : IDisposable, IAsyncDisposable
{
@ -35,9 +35,7 @@ namespace Kyoo.Tests
public RepositoryActivator(ITestOutputHelper output, PostgresFixture postgres = null)
{
Context = postgres == null
? new SqLiteTestContext(output)
: new PostgresTestContext(postgres, output);
Context = new PostgresTestContext(postgres, output);
ProviderRepository provider = new(_NewContext());
LibraryRepository library = new(_NewContext(), provider);

View File

@ -27,7 +27,7 @@ using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Xunit;
namespace Kyoo.Tests
namespace Kyoo.Tests.Database
{
public abstract class RepositoryTests<T> : IDisposable, IAsyncDisposable
where T : class, IResource, new()

View File

@ -20,8 +20,6 @@ using System;
using System.Threading.Tasks;
using Kyoo.Database;
using Kyoo.Postgresql;
using Kyoo.SqLite;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Npgsql;
@ -30,55 +28,6 @@ using Xunit.Abstractions;
namespace Kyoo.Tests
{
public sealed class SqLiteTestContext : TestContext
{
/// <summary>
/// The internal sqlite connection used by all context returned by this class.
/// </summary>
private readonly SqliteConnection _connection;
/// <summary>
/// The context's options that specify to use an in memory Sqlite database.
/// </summary>
private readonly DbContextOptions<DatabaseContext> _context;
public SqLiteTestContext(ITestOutputHelper output)
{
_connection = new SqliteConnection("DataSource=:memory:");
_connection.Open();
_context = new DbContextOptionsBuilder<DatabaseContext>()
.UseSqlite(_connection)
.UseLoggerFactory(LoggerFactory.Create(x =>
{
x.ClearProviders();
x.AddXunit(output);
}))
.EnableSensitiveDataLogging()
.EnableDetailedErrors()
.Options;
using DatabaseContext context = New();
context.Database.Migrate();
TestSample.FillDatabase(context);
}
public override void Dispose()
{
_connection.Close();
}
public override async ValueTask DisposeAsync()
{
await _connection.CloseAsync();
}
public override DatabaseContext New()
{
return new SqLiteContext(_context);
}
}
[CollectionDefinition(nameof(Postgresql))]
public class PostgresCollection : ICollectionFixture<PostgresFixture>
{ }

View File

@ -29,7 +29,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../src/Kyoo.Database/Kyoo.Database.csproj" />
<ProjectReference Include="../../src/Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
<ProjectReference Include="../../src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj" />
<ProjectReference Include="../../src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj" />

View File

@ -4,13 +4,9 @@ services:
back:
build: ./back
restart: on-failure
environment:
env_file:
- ./.env
- KYOO_DATADIR=/var/lib/kyoo
- DATABASE__ENABLED=postgres
- DATABASE__CONFIGURATIONS__POSTGRES__SERVER=postgres
- DATABASE__CONFIGURATIONS__POSTGRES__USER=${POSTGRES_USER}
- DATABASE__CONFIGURATIONS__POSTGRES__PASSWORD=${POSTGRES_PASSWORD}
- DATABASE__CONFIGURATIONS__POSTGRES__DATABASE=${POSTGRES_DB}
- TVDB__APIKEY=${TVDB__APIKEY}
- THEMOVIEDB__APIKEY=${THEMOVIEDB__APIKEY}
- LIBRARY_ROOT=/video
@ -43,10 +39,8 @@ services:
postgres:
image: postgres
restart: on-failure
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
env_file:
- ./.env
volumes:
- db:/var/lib/postgresql/data