diff --git a/src/NuGet.config b/src/NuGet.config
index d09664bf0..47d68eb1d 100644
--- a/src/NuGet.config
+++ b/src/NuGet.config
@@ -7,6 +7,5 @@
-
diff --git a/src/NzbDrone.Core/Datastore/Migration/000_database_engine_version_check.cs b/src/NzbDrone.Core/Datastore/Migration/000_database_engine_version_check.cs
index 93bfc0afc..343bf3cde 100644
--- a/src/NzbDrone.Core/Datastore/Migration/000_database_engine_version_check.cs
+++ b/src/NzbDrone.Core/Datastore/Migration/000_database_engine_version_check.cs
@@ -7,7 +7,7 @@
namespace NzbDrone.Core.Datastore.Migration
{
[Maintenance(MigrationStage.BeforeAll, TransactionBehavior.None)]
- public class DatabaseEngineVersionCheck : FluentMigrator.Migration
+ public class DatabaseEngineVersionCheck : ForwardOnlyMigration
{
protected readonly Logger _logger;
@@ -22,11 +22,6 @@ public override void Up()
IfDatabase("postgres").Execute.WithConnection(LogPostgresVersion);
}
- public override void Down()
- {
- // No-op
- }
-
private void LogSqliteVersion(IDbConnection conn, IDbTransaction tran)
{
using (var versionCmd = conn.CreateCommand())
diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs
index 992f2a26f..dfdbf5217 100644
--- a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs
+++ b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationController.cs
@@ -6,7 +6,6 @@
using FluentMigrator.Runner.Initialization;
using FluentMigrator.Runner.Processors;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
using NLog;
using NLog.Extensions.Logging;
@@ -20,13 +19,10 @@ public interface IMigrationController
public class MigrationController : IMigrationController
{
private readonly Logger _logger;
- private readonly ILoggerProvider _migrationLoggerProvider;
- public MigrationController(Logger logger,
- ILoggerProvider migrationLoggerProvider)
+ public MigrationController(Logger logger)
{
_logger = logger;
- _migrationLoggerProvider = migrationLoggerProvider;
}
public void Migrate(string connectionString, MigrationContext migrationContext, DatabaseType databaseType)
@@ -35,16 +31,13 @@ public void Migrate(string connectionString, MigrationContext migrationContext,
_logger.Info("*** Migrating {0} ***", connectionString);
- ServiceProvider serviceProvider;
-
var db = databaseType == DatabaseType.SQLite ? "sqlite" : "postgres";
- serviceProvider = new ServiceCollection()
+ var serviceProvider = new ServiceCollection()
.AddLogging(b => b.AddNLog())
.AddFluentMigratorCore()
.Configure(cfg => cfg.IncludeUntaggedMaintenances = true)
- .ConfigureRunner(
- builder => builder
+ .ConfigureRunner(builder => builder
.AddPostgres()
.AddNzbDroneSQLite()
.WithGlobalConnectionString(connectionString)
diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationExtension.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationExtension.cs
index 3607ca1d7..ab390f6f7 100644
--- a/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationExtension.cs
+++ b/src/NzbDrone.Core/Datastore/Migration/Framework/MigrationExtension.cs
@@ -4,9 +4,14 @@
using FluentMigrator.Builders.Create.Table;
using FluentMigrator.Runner;
using FluentMigrator.Runner.BatchParser;
+using FluentMigrator.Runner.Generators;
using FluentMigrator.Runner.Generators.SQLite;
+using FluentMigrator.Runner.Initialization;
+using FluentMigrator.Runner.Processors;
using FluentMigrator.Runner.Processors.SQLite;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
namespace NzbDrone.Core.Datastore.Migration.Framework
{
@@ -26,23 +31,40 @@ public static IDbCommand CreateCommand(this IDbConnection conn, IDbTransaction t
return command;
}
- public static void AddParameter(this System.Data.IDbCommand command, object value)
+ public static void AddParameter(this IDbCommand command, object value)
{
var parameter = command.CreateParameter();
parameter.Value = value;
command.Parameters.Add(parameter);
}
- public static IMigrationRunnerBuilder AddNzbDroneSQLite(this IMigrationRunnerBuilder builder)
+ public static IMigrationRunnerBuilder AddNzbDroneSQLite(this IMigrationRunnerBuilder builder, bool binaryGuid = false, bool useStrictTables = false)
{
builder.Services
.AddTransient()
.AddScoped()
- .AddScoped()
+ .AddScoped(sp =>
+ {
+ var factory = sp.GetService();
+ var logger = sp.GetService>();
+ var options = sp.GetService>();
+ var connectionStringAccessor = sp.GetService();
+ var sqliteQuoter = new SQLiteQuoter(false);
+ return new NzbDroneSQLiteProcessor(factory, sp.GetService(), logger, options, connectionStringAccessor, sp, sqliteQuoter);
+ })
+ .AddScoped(_ => new NzbDroneSQLiteTypeMap(useStrictTables))
.AddScoped(sp => sp.GetRequiredService())
- .AddScoped()
- .AddScoped()
+ .AddScoped(
+ sp =>
+ {
+ var typeMap = sp.GetRequiredService();
+ return new SQLiteGenerator(
+ new SQLiteQuoter(binaryGuid),
+ typeMap,
+ new OptionsWrapper(new GeneratorOptions()));
+ })
.AddScoped(sp => sp.GetRequiredService());
+
return builder;
}
}
diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteProcessor.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteProcessor.cs
index e3f776e58..9acb0ec7c 100644
--- a/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteProcessor.cs
+++ b/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteProcessor.cs
@@ -15,15 +15,18 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
{
public class NzbDroneSQLiteProcessor : SQLiteProcessor
{
+ private readonly SQLiteQuoter _quoter;
+
public NzbDroneSQLiteProcessor(SQLiteDbFactory factory,
SQLiteGenerator generator,
ILogger logger,
IOptionsSnapshot options,
IConnectionStringAccessor connectionStringAccessor,
IServiceProvider serviceProvider,
- SQLiteQuoter sqliteQuoter)
- : base(factory, generator, logger, options, connectionStringAccessor, serviceProvider, sqliteQuoter)
+ SQLiteQuoter quoter)
+ : base(factory, generator, logger, options, connectionStringAccessor, serviceProvider, quoter)
{
+ _quoter = quoter;
}
public override void Process(AlterColumnExpression expression)
@@ -35,7 +38,7 @@ public override void Process(AlterColumnExpression expression)
if (columnIndex == -1)
{
- throw new ApplicationException(string.Format("Column {0} does not exist on table {1}.", expression.Column.Name, expression.TableName));
+ throw new ApplicationException($"Column {expression.Column.Name} does not exist on table {expression.TableName}.");
}
columnDefinitions[columnIndex] = expression.Column;
@@ -45,6 +48,28 @@ public override void Process(AlterColumnExpression expression)
ProcessAlterTable(tableDefinition);
}
+ public override void Process(AlterDefaultConstraintExpression expression)
+ {
+ var tableDefinition = GetTableSchema(expression.TableName);
+
+ var columnDefinitions = tableDefinition.Columns.ToList();
+ var columnIndex = columnDefinitions.FindIndex(c => c.Name == expression.ColumnName);
+
+ if (columnIndex == -1)
+ {
+ throw new ApplicationException($"Column {expression.ColumnName} does not exist on table {expression.TableName}.");
+ }
+
+ var changedColumn = columnDefinitions[columnIndex];
+ changedColumn.DefaultValue = expression.DefaultValue;
+
+ columnDefinitions[columnIndex] = changedColumn;
+
+ tableDefinition.Columns = columnDefinitions;
+
+ ProcessAlterTable(tableDefinition);
+ }
+
public override void Process(DeleteColumnExpression expression)
{
var tableDefinition = GetTableSchema(expression.TableName);
@@ -62,7 +87,7 @@ public override void Process(DeleteColumnExpression expression)
if (columnsToRemove.Any())
{
- throw new ApplicationException(string.Format("Column {0} does not exist on table {1}.", columnsToRemove.First(), expression.TableName));
+ throw new ApplicationException($"Column {columnsToRemove.First()} does not exist on table {expression.TableName}.");
}
ProcessAlterTable(tableDefinition);
@@ -78,12 +103,12 @@ public override void Process(RenameColumnExpression expression)
if (columnIndex == -1)
{
- throw new ApplicationException(string.Format("Column {0} does not exist on table {1}.", expression.OldName, expression.TableName));
+ throw new ApplicationException($"Column {expression.OldName} does not exist on table {expression.TableName}.");
}
if (columnDefinitions.Any(c => c.Name == expression.NewName))
{
- throw new ApplicationException(string.Format("Column {0} already exists on table {1}.", expression.NewName, expression.TableName));
+ throw new ApplicationException($"Column {expression.NewName} already exists on table {expression.TableName}.");
}
oldColumnDefinitions[columnIndex] = (ColumnDefinition)columnDefinitions[columnIndex].Clone();
@@ -128,21 +153,20 @@ protected virtual void ProcessAlterTable(TableDefinition tableDefinition, List quoter.QuoteColumnName(c.Name)));
- var columnsToFetch = string.Join(", ", (oldColumnDefinitions ?? tableDefinition.Columns).Select(c => quoter.QuoteColumnName(c.Name)));
+ var columnsToInsert = string.Join(", ", tableDefinition.Columns.Select(c => _quoter.QuoteColumnName(c.Name)));
+ var columnsToFetch = string.Join(", ", (oldColumnDefinitions ?? tableDefinition.Columns).Select(c => _quoter.QuoteColumnName(c.Name)));
- Process(new CreateTableExpression() { TableName = tempTableName, Columns = tableDefinition.Columns.ToList() });
+ Process(new CreateTableExpression { TableName = tempTableName, Columns = tableDefinition.Columns.ToList() });
- Process(string.Format("INSERT INTO {0} ({1}) SELECT {2} FROM {3}", quoter.QuoteTableName(tempTableName), columnsToInsert, columnsToFetch, quoter.QuoteTableName(tableName)));
+ Process($"INSERT INTO {_quoter.QuoteTableName(tempTableName)} ({columnsToInsert}) SELECT {columnsToFetch} FROM {_quoter.QuoteTableName(tableName)}");
- Process(new DeleteTableExpression() { TableName = tableName });
+ Process(new DeleteTableExpression { TableName = tableName });
- Process(new RenameTableExpression() { OldName = tempTableName, NewName = tableName });
+ Process(new RenameTableExpression { OldName = tempTableName, NewName = tableName });
foreach (var index in tableDefinition.Indexes)
{
- Process(new CreateIndexExpression() { Index = index });
+ Process(new CreateIndexExpression { Index = index });
}
}
}
diff --git a/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteTypeMap.cs b/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteTypeMap.cs
new file mode 100644
index 000000000..2e431e2df
--- /dev/null
+++ b/src/NzbDrone.Core/Datastore/Migration/Framework/NzbDroneSQLiteTypeMap.cs
@@ -0,0 +1,76 @@
+using System.Data;
+using FluentMigrator.Runner.Generators.Base;
+using FluentMigrator.Runner.Generators.SQLite;
+
+namespace NzbDrone.Core.Datastore.Migration.Framework;
+
+// Based on https://github.com/fluentmigrator/fluentmigrator/blob/v6.2.0/src/FluentMigrator.Runner.SQLite/Generators/SQLite/SQLiteTypeMap.cs
+public sealed class NzbDroneSQLiteTypeMap : TypeMapBase, ISQLiteTypeMap
+{
+ public bool UseStrictTables { get; }
+
+ public NzbDroneSQLiteTypeMap(bool useStrictTables = false)
+ {
+ UseStrictTables = useStrictTables;
+
+ SetupTypeMaps();
+ }
+
+ // Must be kept in sync with upstream
+ protected override void SetupTypeMaps()
+ {
+ SetTypeMap(DbType.Binary, "BLOB");
+ SetTypeMap(DbType.Byte, "INTEGER");
+ SetTypeMap(DbType.Int16, "INTEGER");
+ SetTypeMap(DbType.Int32, "INTEGER");
+ SetTypeMap(DbType.Int64, "INTEGER");
+ SetTypeMap(DbType.SByte, "INTEGER");
+ SetTypeMap(DbType.UInt16, "INTEGER");
+ SetTypeMap(DbType.UInt32, "INTEGER");
+ SetTypeMap(DbType.UInt64, "INTEGER");
+
+ if (!UseStrictTables)
+ {
+ SetTypeMap(DbType.Currency, "NUMERIC");
+ SetTypeMap(DbType.Decimal, "NUMERIC");
+ SetTypeMap(DbType.Double, "NUMERIC");
+ SetTypeMap(DbType.Single, "NUMERIC");
+ SetTypeMap(DbType.VarNumeric, "NUMERIC");
+ SetTypeMap(DbType.Date, "DATETIME");
+ SetTypeMap(DbType.DateTime, "DATETIME");
+ SetTypeMap(DbType.DateTime2, "DATETIME");
+ SetTypeMap(DbType.Time, "DATETIME");
+ SetTypeMap(DbType.Guid, "UNIQUEIDENTIFIER");
+
+ // Custom so that we can use DateTimeOffset in Postgres for appropriate DB typing
+ SetTypeMap(DbType.DateTimeOffset, "DATETIME");
+ }
+ else
+ {
+ SetTypeMap(DbType.Currency, "TEXT");
+ SetTypeMap(DbType.Decimal, "TEXT");
+ SetTypeMap(DbType.Double, "REAL");
+ SetTypeMap(DbType.Single, "REAL");
+ SetTypeMap(DbType.VarNumeric, "TEXT");
+ SetTypeMap(DbType.Date, "TEXT");
+ SetTypeMap(DbType.DateTime, "TEXT");
+ SetTypeMap(DbType.DateTime2, "TEXT");
+ SetTypeMap(DbType.Time, "TEXT");
+ SetTypeMap(DbType.Guid, "TEXT");
+
+ // Custom so that we can use DateTimeOffset in Postgres for appropriate DB typing
+ SetTypeMap(DbType.DateTimeOffset, "TEXT");
+ }
+
+ SetTypeMap(DbType.AnsiString, "TEXT");
+ SetTypeMap(DbType.String, "TEXT");
+ SetTypeMap(DbType.AnsiStringFixedLength, "TEXT");
+ SetTypeMap(DbType.StringFixedLength, "TEXT");
+ SetTypeMap(DbType.Boolean, "INTEGER");
+ }
+
+ public override string GetTypeMap(DbType type, int? size, int? precision)
+ {
+ return base.GetTypeMap(type, size: null, precision: null);
+ }
+}
diff --git a/src/NzbDrone.Core/Lidarr.Core.csproj b/src/NzbDrone.Core/Lidarr.Core.csproj
index 0723b4d34..470a415df 100644
--- a/src/NzbDrone.Core/Lidarr.Core.csproj
+++ b/src/NzbDrone.Core/Lidarr.Core.csproj
@@ -15,9 +15,9 @@
-
-
-
+
+
+