mirror of https://github.com/lidarr/Lidarr
150 lines
6.1 KiB
C#
150 lines
6.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using FluentMigrator.Expressions;
|
|
using FluentMigrator.Model;
|
|
using FluentMigrator.Runner.Generators.SQLite;
|
|
using FluentMigrator.Runner.Initialization;
|
|
using FluentMigrator.Runner.Processors;
|
|
using FluentMigrator.Runner.Processors.SQLite;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace NzbDrone.Core.Datastore.Migration.Framework
|
|
{
|
|
public class NzbDroneSQLiteProcessor : SQLiteProcessor
|
|
{
|
|
public NzbDroneSQLiteProcessor(SQLiteDbFactory factory,
|
|
SQLiteGenerator generator,
|
|
ILogger<NzbDroneSQLiteProcessor> logger,
|
|
IOptionsSnapshot<ProcessorOptions> options,
|
|
IConnectionStringAccessor connectionStringAccessor,
|
|
IServiceProvider serviceProvider,
|
|
SQLiteQuoter sqliteQuoter)
|
|
: base(factory, generator, logger, options, connectionStringAccessor, serviceProvider, sqliteQuoter)
|
|
{
|
|
}
|
|
|
|
public override void Process(AlterColumnExpression expression)
|
|
{
|
|
var tableDefinition = GetTableSchema(expression.TableName);
|
|
|
|
var columnDefinitions = tableDefinition.Columns.ToList();
|
|
var columnIndex = columnDefinitions.FindIndex(c => c.Name == expression.Column.Name);
|
|
|
|
if (columnIndex == -1)
|
|
{
|
|
throw new ApplicationException(string.Format("Column {0} does not exist on table {1}.", expression.Column.Name, expression.TableName));
|
|
}
|
|
|
|
columnDefinitions[columnIndex] = expression.Column;
|
|
|
|
tableDefinition.Columns = columnDefinitions;
|
|
|
|
ProcessAlterTable(tableDefinition);
|
|
}
|
|
|
|
public override void Process(DeleteColumnExpression expression)
|
|
{
|
|
var tableDefinition = GetTableSchema(expression.TableName);
|
|
|
|
var columnDefinitions = tableDefinition.Columns.ToList();
|
|
var indexDefinitions = tableDefinition.Indexes.ToList();
|
|
|
|
var columnsToRemove = expression.ColumnNames.ToList();
|
|
|
|
columnDefinitions.RemoveAll(c => columnsToRemove.Remove(c.Name));
|
|
indexDefinitions.RemoveAll(i => i.Columns.Any(c => expression.ColumnNames.Contains(c.Name)));
|
|
|
|
tableDefinition.Columns = columnDefinitions;
|
|
tableDefinition.Indexes = indexDefinitions;
|
|
|
|
if (columnsToRemove.Any())
|
|
{
|
|
throw new ApplicationException(string.Format("Column {0} does not exist on table {1}.", columnsToRemove.First(), expression.TableName));
|
|
}
|
|
|
|
ProcessAlterTable(tableDefinition);
|
|
}
|
|
|
|
public override void Process(RenameColumnExpression expression)
|
|
{
|
|
var tableDefinition = GetTableSchema(expression.TableName);
|
|
|
|
var oldColumnDefinitions = tableDefinition.Columns.ToList();
|
|
var columnDefinitions = tableDefinition.Columns.ToList();
|
|
var columnIndex = columnDefinitions.FindIndex(c => c.Name == expression.OldName);
|
|
|
|
if (columnIndex == -1)
|
|
{
|
|
throw new ApplicationException(string.Format("Column {0} does not exist on table {1}.", expression.OldName, 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));
|
|
}
|
|
|
|
oldColumnDefinitions[columnIndex] = (ColumnDefinition)columnDefinitions[columnIndex].Clone();
|
|
columnDefinitions[columnIndex].Name = expression.NewName;
|
|
|
|
foreach (var index in tableDefinition.Indexes)
|
|
{
|
|
if (index.Name.StartsWith("IX_"))
|
|
{
|
|
index.Name = Regex.Replace(index.Name, "(?<=_)" + Regex.Escape(expression.OldName) + "(?=_|$)", Regex.Escape(expression.NewName));
|
|
}
|
|
|
|
foreach (var column in index.Columns)
|
|
{
|
|
if (column.Name == expression.OldName)
|
|
{
|
|
column.Name = expression.NewName;
|
|
}
|
|
}
|
|
}
|
|
|
|
ProcessAlterTable(tableDefinition, oldColumnDefinitions);
|
|
}
|
|
|
|
protected virtual TableDefinition GetTableSchema(string tableName)
|
|
{
|
|
var schemaDumper = new SqliteSchemaDumper(this);
|
|
var schema = schemaDumper.ReadDbSchema();
|
|
|
|
return schema.Single(v => v.Name == tableName);
|
|
}
|
|
|
|
protected virtual void ProcessAlterTable(TableDefinition tableDefinition, List<ColumnDefinition> oldColumnDefinitions = null)
|
|
{
|
|
var tableName = tableDefinition.Name;
|
|
var tempTableName = tableName + "_temp";
|
|
|
|
var uid = 0;
|
|
while (TableExists(null, tempTableName))
|
|
{
|
|
tempTableName = tableName + "_temp" + uid++;
|
|
}
|
|
|
|
// What is the cleanest way to do this? Add function to Generator?
|
|
var quoter = new SQLiteQuoter();
|
|
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(string.Format("INSERT INTO {0} ({1}) SELECT {2} FROM {3}", quoter.QuoteTableName(tempTableName), columnsToInsert, columnsToFetch, quoter.QuoteTableName(tableName)));
|
|
|
|
Process(new DeleteTableExpression() { TableName = tableName });
|
|
|
|
Process(new RenameTableExpression() { OldName = tempTableName, NewName = tableName });
|
|
|
|
foreach (var index in tableDefinition.Indexes)
|
|
{
|
|
Process(new CreateIndexExpression() { Index = index });
|
|
}
|
|
}
|
|
}
|
|
}
|