You've already forked Sonarr
							
							
				mirror of
				https://github.com/Sonarr/Sonarr.git
				synced 2025-10-31 00:07:55 +02:00 
			
		
		
		
	added support for removing columns
This commit is contained in:
		| @@ -1,49 +0,0 @@ | ||||
| using System.Linq; | ||||
| using FluentAssertions; | ||||
| using NUnit.Framework; | ||||
| using NzbDrone.Core.Datastore; | ||||
| using NzbDrone.Core.Datastore.Migration.Framework; | ||||
| using NzbDrone.Core.Test.Framework; | ||||
|  | ||||
| namespace NzbDrone.Core.Test.Datastore | ||||
| { | ||||
|     [TestFixture] | ||||
|     public class SQLiteAlterFixture : DbTest | ||||
|     { | ||||
|         private SQLiteAlter Subject; | ||||
|  | ||||
|         [SetUp] | ||||
|         public void SetUp() | ||||
|         { | ||||
|             var connection = Mocker.Resolve<IDatabase>().DataMapper.ConnectionString; | ||||
|             Subject = new SQLiteAlter(connection); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         [Test] | ||||
|         public void should_parse_existing_columns() | ||||
|         { | ||||
|             var columns = Subject.GetColumns("Series"); | ||||
|  | ||||
|             columns.Should().NotBeEmpty(); | ||||
|  | ||||
|             columns.Values.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Name)); | ||||
|             columns.Values.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Schema)); | ||||
|         } | ||||
|  | ||||
|         [Test] | ||||
|         public void should_create_table_from_column_list() | ||||
|         { | ||||
|             var columns = Subject.GetColumns("Series"); | ||||
|             columns.Remove("Title"); | ||||
|  | ||||
|             Subject.CreateTable("Series_New", columns.Values); | ||||
|  | ||||
|             var newColumns = Subject.GetColumns("Series_New"); | ||||
|  | ||||
|             newColumns.Values.Should().HaveSameCount(columns.Values); | ||||
|             newColumns.Should().NotContainKey("Title"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										84
									
								
								NzbDrone.Core.Test/Datastore/SQLiteMigrationHelperFixture.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								NzbDrone.Core.Test/Datastore/SQLiteMigrationHelperFixture.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| using FizzWare.NBuilder; | ||||
| using FluentAssertions; | ||||
| using NUnit.Framework; | ||||
| using NzbDrone.Core.Datastore.Migration.Framework; | ||||
| using NzbDrone.Core.Test.Framework; | ||||
| using NzbDrone.Core.Tv; | ||||
|  | ||||
| namespace NzbDrone.Core.Test.Datastore | ||||
| { | ||||
|     [TestFixture] | ||||
|     public class SQLiteMigrationHelperFixture : DbTest | ||||
|     { | ||||
|         private SQLiteMigrationHelper _subject; | ||||
|  | ||||
|         [SetUp] | ||||
|         public void SetUp() | ||||
|         { | ||||
|             _subject = Mocker.Resolve<SQLiteMigrationHelper>(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         [Test] | ||||
|         public void should_parse_existing_columns() | ||||
|         { | ||||
|             var columns = _subject.GetColumns("Series"); | ||||
|  | ||||
|             columns.Should().NotBeEmpty(); | ||||
|  | ||||
|             columns.Values.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Name)); | ||||
|             columns.Values.Should().NotContain(c => string.IsNullOrWhiteSpace(c.Schema)); | ||||
|         } | ||||
|  | ||||
|         [Test] | ||||
|         public void should_create_table_from_column_list() | ||||
|         { | ||||
|             var columns = _subject.GetColumns("Series"); | ||||
|             columns.Remove("Title"); | ||||
|  | ||||
|             _subject.CreateTable("Series_New", columns.Values); | ||||
|  | ||||
|             var newColumns = _subject.GetColumns("Series_New"); | ||||
|  | ||||
|             newColumns.Values.Should().HaveSameCount(columns.Values); | ||||
|             newColumns.Should().NotContainKey("Title"); | ||||
|         } | ||||
|  | ||||
|         [Test] | ||||
|         public void should_get_zero_count_on_empty_table() | ||||
|         { | ||||
|             _subject.GetRowCount("Series").Should().Be(0); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         [Test] | ||||
|         public void should_be_able_to_transfer_empty_tables() | ||||
|         { | ||||
|             var columns = _subject.GetColumns("Series"); | ||||
|             columns.Remove("Title"); | ||||
|  | ||||
|             _subject.CreateTable("Series_New", columns.Values); | ||||
|  | ||||
|  | ||||
|             _subject.CopyData("Series", "Series_New", columns.Values); | ||||
|         } | ||||
|  | ||||
|         [Test] | ||||
|         public void should_transfer_table_with_data() | ||||
|         { | ||||
|             var originalEpisodes = Builder<Episode>.CreateListOfSize(10).BuildListOfNew(); | ||||
|  | ||||
|             Mocker.Resolve<EpisodeRepository>().InsertMany(originalEpisodes); | ||||
|  | ||||
|             var columns = _subject.GetColumns("Episodes"); | ||||
|             columns.Remove("Title"); | ||||
|  | ||||
|             _subject.CreateTable("Episodes_New", columns.Values); | ||||
|  | ||||
|             _subject.CopyData("Episodes", "Episodes_New", columns.Values); | ||||
|  | ||||
|             _subject.GetRowCount("Episodes_New").Should().Be(originalEpisodes.Count); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -2,6 +2,7 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using FluentMigrator.Runner; | ||||
| using Marr.Data; | ||||
| using Moq; | ||||
| using NUnit.Framework; | ||||
| @@ -93,10 +94,16 @@ namespace NzbDrone.Core.Test.Framework | ||||
|             WithTempAsAppPath(); | ||||
|  | ||||
|  | ||||
|             Mocker.SetConstant<IAnnouncer>(Mocker.Resolve<MigrationLogger>()); | ||||
|             Mocker.SetConstant<IConnectionStringFactory>(Mocker.Resolve<ConnectionStringFactory>()); | ||||
|             Mocker.SetConstant<ISQLiteMigrationHelper>(Mocker.Resolve<SQLiteMigrationHelper>()); | ||||
|             Mocker.SetConstant<ISQLiteAlter>(Mocker.Resolve<SQLiteAlter>()); | ||||
|             Mocker.SetConstant<IMigrationController>(Mocker.Resolve<MigrationController>()); | ||||
|  | ||||
|             MapRepository.Instance.EnableTraceLogging = true; | ||||
|  | ||||
|             var factory = new DbFactory(new MigrationController(new MigrationLogger(TestLogger)), Mocker.GetMock<IAppDirectoryInfo>().Object); | ||||
|             _database = factory.Create(MigrationType); | ||||
|             var factory = Mocker.Resolve<DbFactory>(); | ||||
|             var _database = factory.Create(MigrationType); | ||||
|             _db = new TestDatabase(_database); | ||||
|             Mocker.SetConstant(_database); | ||||
|         } | ||||
|   | ||||
| @@ -124,7 +124,7 @@ | ||||
|     <Compile Include="Datastore\PagingSpecExtenstionsTests\ToSortDirectionFixture.cs" /> | ||||
|     <Compile Include="Datastore\PagingSpecExtenstionsTests\PagingOffsetFixture.cs" /> | ||||
|     <Compile Include="Datastore\ReflectionStrategyFixture\Benchmarks.cs" /> | ||||
|     <Compile Include="Datastore\SQLiteAlterFixture.cs" /> | ||||
|     <Compile Include="Datastore\SQLiteMigrationHelperFixture.cs" /> | ||||
|     <Compile Include="DecisionEngineTests\NotRestrictedNzbSpecificationFixture.cs" /> | ||||
|     <Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" /> | ||||
|     <Compile Include="Download\DownloadApprovedReportsTests\GetQualifiedReportsFixture.cs" /> | ||||
|   | ||||
							
								
								
									
										37
									
								
								NzbDrone.Core/Datastore/ConnectionStringFactory.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								NzbDrone.Core/Datastore/ConnectionStringFactory.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| using System; | ||||
| using System.Data.SQLite; | ||||
| using NzbDrone.Common; | ||||
| using NzbDrone.Common.EnvironmentInfo; | ||||
|  | ||||
| namespace NzbDrone.Core.Datastore | ||||
| { | ||||
|     public interface IConnectionStringFactory | ||||
|     { | ||||
|         string MainDbConnectionString { get; } | ||||
|         string LogDbConnectionString { get; } | ||||
|     } | ||||
|  | ||||
|     public class ConnectionStringFactory : IConnectionStringFactory | ||||
|     { | ||||
|         public ConnectionStringFactory(IAppDirectoryInfo appDirectoryInfo) | ||||
|         { | ||||
|             MainDbConnectionString = GetConnectionString(appDirectoryInfo.GetNzbDroneDatabase()); | ||||
|             LogDbConnectionString = GetConnectionString(appDirectoryInfo.GetLogDatabase()); | ||||
|         } | ||||
|  | ||||
|         public string MainDbConnectionString { get; private set; } | ||||
|         public string LogDbConnectionString { get; private set; } | ||||
|  | ||||
|         private static string GetConnectionString(string dbPath) | ||||
|         { | ||||
|             var connectionBuilder = new SQLiteConnectionStringBuilder(); | ||||
|  | ||||
|             connectionBuilder.DataSource = dbPath; | ||||
|             connectionBuilder.CacheSize = (int)-10.Megabytes(); | ||||
|             connectionBuilder.DateTimeKind = DateTimeKind.Utc; | ||||
|             connectionBuilder.JournalMode = SQLiteJournalModeEnum.Wal; | ||||
|  | ||||
|             return connectionBuilder.ConnectionString; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -3,10 +3,8 @@ using System.Data.SQLite; | ||||
| using Marr.Data; | ||||
| using Marr.Data.Reflection; | ||||
| using NzbDrone.Common.Composition; | ||||
| using NzbDrone.Common.EnvironmentInfo; | ||||
| using NzbDrone.Common.Messaging; | ||||
| using NzbDrone.Core.Datastore.Migration.Framework; | ||||
| using NzbDrone.Common; | ||||
| using NzbDrone.Core.Instrumentation; | ||||
|  | ||||
|  | ||||
| @@ -17,10 +15,11 @@ namespace NzbDrone.Core.Datastore | ||||
|         IDatabase Create(MigrationType migrationType = MigrationType.Main); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public class DbFactory : IDbFactory | ||||
|     { | ||||
|         private readonly IMigrationController _migrationController; | ||||
|         private readonly IAppDirectoryInfo _appDirectoryInfo; | ||||
|         private readonly IConnectionStringFactory _connectionStringFactory; | ||||
|  | ||||
|         static DbFactory() | ||||
|         { | ||||
| @@ -39,26 +38,27 @@ namespace NzbDrone.Core.Datastore | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         public DbFactory(IMigrationController migrationController, IAppDirectoryInfo appDirectoryInfo) | ||||
|         public DbFactory(IMigrationController migrationController, IConnectionStringFactory connectionStringFactory) | ||||
|         { | ||||
|             _migrationController = migrationController; | ||||
|             _appDirectoryInfo = appDirectoryInfo; | ||||
|             _connectionStringFactory = connectionStringFactory; | ||||
|         } | ||||
|  | ||||
|         public IDatabase Create(MigrationType migrationType = MigrationType.Main) | ||||
|         { | ||||
|             string dbPath; | ||||
|             string connectionString; | ||||
|  | ||||
|  | ||||
|             switch (migrationType) | ||||
|             { | ||||
|                 case MigrationType.Main: | ||||
|                     { | ||||
|                         dbPath = _appDirectoryInfo.GetNzbDroneDatabase(); | ||||
|                         connectionString = _connectionStringFactory.MainDbConnectionString; | ||||
|                         break; | ||||
|                     } | ||||
|                 case MigrationType.Log: | ||||
|                     { | ||||
|                         dbPath = _appDirectoryInfo.GetLogDatabase(); | ||||
|                         connectionString = _connectionStringFactory.LogDbConnectionString; | ||||
|                         break; | ||||
|                     } | ||||
|                 default: | ||||
| @@ -68,7 +68,6 @@ namespace NzbDrone.Core.Datastore | ||||
|             } | ||||
|  | ||||
|  | ||||
|             var connectionString = GetConnectionString(dbPath); | ||||
|  | ||||
|             _migrationController.MigrateToLatest(connectionString, migrationType); | ||||
|  | ||||
| @@ -82,17 +81,5 @@ namespace NzbDrone.Core.Datastore | ||||
|                     return dataMapper; | ||||
|                 }); | ||||
|         } | ||||
|  | ||||
|         private string GetConnectionString(string dbPath) | ||||
|         { | ||||
|             var connectionBuilder = new SQLiteConnectionStringBuilder(); | ||||
|  | ||||
|             connectionBuilder.DataSource = dbPath; | ||||
|             connectionBuilder.CacheSize = (int)-10.Megabytes(); | ||||
|             connectionBuilder.DateTimeKind = DateTimeKind.Utc; | ||||
|             connectionBuilder.JournalMode = SQLiteJournalModeEnum.Wal; | ||||
|  | ||||
|             return connectionBuilder.ConnectionString; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,24 +3,13 @@ using NzbDrone.Core.Datastore.Migration.Framework; | ||||
|  | ||||
| namespace NzbDrone.Core.Datastore.Migration | ||||
| { | ||||
| /*    [Tags("")] | ||||
|     [Tags("")] | ||||
|     [Migration(7)] | ||||
|     public class remove_backlog : NzbDroneMigrationBase | ||||
|     { | ||||
|         protected override void MainDbUpgrade() | ||||
|         { | ||||
|             var newSeriesTable = "CREATE TABLE [Series_new] ([Id] integer NOT NULL PRIMARY KEY AUTOINCREMENT, [TvdbId] integer NOT NULL, " + | ||||
|                                  "[TvRageId] integer NOT NULL, [ImdbId] text NOT NULL, [Title] text NOT NULL, [TitleSlug] text NOT NULL, " + | ||||
|                                  "[CleanTitle] text NOT NULL, [Status] integer NOT NULL, [Overview] text, [AirTime] text, " + | ||||
|                                  "[Images] text NOT NULL, [Path] text NOT NULL, [Monitored] integer NOT NULL, [QualityProfileId] integer NOT NULL, " + | ||||
|                                  "[SeasonFolder] integer NOT NULL, [LastInfoSync] datetime, [LastDiskSync] datetime, [Runtime] integer NOT NULL, " + | ||||
|                                  "[SeriesType] integer NOT NULL, [Network] text, [CustomStartDate] datetime, " + | ||||
|                                  "[UseSceneNumbering] integer NOT NULL, [FirstAired] datetime)"; | ||||
|  | ||||
|             Execute.Sql(newSeriesTable); | ||||
|  | ||||
|  | ||||
|             Execute.Sql("INSERT INTO Series_new SELECT * FROM Series"); | ||||
|             SQLiteAlter.DropColumns("Series", new[] { "BacklogSetting" }); | ||||
|         } | ||||
|     }*/ | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,8 @@ | ||||
| namespace NzbDrone.Core.Datastore.Migration.Framework | ||||
| { | ||||
|     public class MigrationContext | ||||
|     { | ||||
|         public MigrationType MigrationType { get; set; } | ||||
|         public ISQLiteAlter SQLiteAlter { get; set; } | ||||
|     } | ||||
| } | ||||
| @@ -14,12 +14,14 @@ namespace NzbDrone.Core.Datastore.Migration.Framework | ||||
|     public class MigrationController : IMigrationController | ||||
|     { | ||||
|         private readonly IAnnouncer _announcer; | ||||
|         private readonly ISQLiteAlter _sqLiteAlter; | ||||
|  | ||||
|         private static readonly HashSet<string> MigrationCache = new HashSet<string>(); | ||||
|  | ||||
|         public MigrationController(IAnnouncer announcer) | ||||
|         public MigrationController(IAnnouncer announcer, ISQLiteAlter sqLiteAlter) | ||||
|         { | ||||
|             _announcer = announcer; | ||||
|             _sqLiteAlter = sqLiteAlter; | ||||
|         } | ||||
|  | ||||
|         public void MigrateToLatest(string connectionString, MigrationType migrationType) | ||||
| @@ -35,7 +37,11 @@ namespace NzbDrone.Core.Datastore.Migration.Framework | ||||
|                 var migrationContext = new RunnerContext(_announcer) | ||||
|                     { | ||||
|                         Namespace = "NzbDrone.Core.Datastore.Migration", | ||||
|                         ApplicationContext = migrationType | ||||
|                         ApplicationContext = new MigrationContext | ||||
|                             { | ||||
|                                 MigrationType = migrationType, | ||||
|                                 SQLiteAlter = _sqLiteAlter | ||||
|                             } | ||||
|                     }; | ||||
|  | ||||
|                 var options = new MigrationOptions { PreviewOnly = false, Timeout = 60 }; | ||||
|   | ||||
| @@ -14,7 +14,11 @@ namespace NzbDrone.Core.Datastore.Migration.Framework | ||||
|  | ||||
|         public override void Up() | ||||
|         { | ||||
|             switch ((MigrationType)ApplicationContext) | ||||
|             var context = (MigrationContext)ApplicationContext; | ||||
|  | ||||
|             SQLiteAlter = context.SQLiteAlter; | ||||
|  | ||||
|             switch (context.MigrationType) | ||||
|             { | ||||
|                 case MigrationType.Main: | ||||
|                     MainDbUpgrade(); | ||||
| @@ -29,6 +33,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public ISQLiteAlter SQLiteAlter { get; private set; } | ||||
|  | ||||
|         public override void Down() | ||||
|         { | ||||
|   | ||||
| @@ -0,0 +1,134 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Data.SQLite; | ||||
| using System.Linq; | ||||
| using System.Text.RegularExpressions; | ||||
|  | ||||
| namespace NzbDrone.Core.Datastore.Migration.Framework | ||||
| { | ||||
|     public interface ISQLiteMigrationHelper | ||||
|     { | ||||
|         Dictionary<String, SQLiteMigrationHelper.SQLiteColumn> GetColumns(string tableName); | ||||
|         void CreateTable(string tableName, IEnumerable<SQLiteMigrationHelper.SQLiteColumn> values); | ||||
|         void CopyData(string sourceTable, string destinationTable, IEnumerable<SQLiteMigrationHelper.SQLiteColumn> columns); | ||||
|         int GetRowCount(string tableName); | ||||
|         void DropTable(string tableName); | ||||
|         void RenameTable(string tableName, string newName); | ||||
|         SQLiteTransaction BeginTransaction(); | ||||
|     } | ||||
|  | ||||
|     public class SQLiteMigrationHelper : ISQLiteMigrationHelper | ||||
|     { | ||||
|         private readonly SQLiteConnection _connection; | ||||
|  | ||||
|         private static readonly Regex SchemaRegex = new Regex(@"['\""\[](?<name>\w+)['\""\]]\s(?<schema>[\w-\s]+)", | ||||
|             RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline); | ||||
|  | ||||
|         public SQLiteMigrationHelper(IConnectionStringFactory connectionStringFactory) | ||||
|         { | ||||
|             _connection = new SQLiteConnection(connectionStringFactory.MainDbConnectionString); | ||||
|             _connection.Open(); | ||||
|         } | ||||
|  | ||||
|         private string GetOriginalSql(string tableName) | ||||
|         { | ||||
|             var command = | ||||
|                 new SQLiteCommand(string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name ='{0}'", | ||||
|                                                 tableName)); | ||||
|  | ||||
|             command.Connection = _connection; | ||||
|             return (string)command.ExecuteScalar(); | ||||
|         } | ||||
|  | ||||
|         public Dictionary<String, SQLiteColumn> GetColumns(string tableName) | ||||
|         { | ||||
|             var originalSql = GetOriginalSql(tableName); | ||||
|  | ||||
|             var matches = SchemaRegex.Matches(originalSql); | ||||
|  | ||||
|             return matches.Cast<Match>().ToDictionary( | ||||
|                                match => match.Groups["name"].Value.Trim(), | ||||
|                                match => new SQLiteColumn | ||||
|                                    { | ||||
|                                        Name = match.Groups["name"].Value.Trim(), | ||||
|                                        Schema = match.Groups["schema"].Value.Trim() | ||||
|                                    }); | ||||
|         } | ||||
|  | ||||
|         public void CreateTable(string tableName, IEnumerable<SQLiteColumn> values) | ||||
|         { | ||||
|             var columns = String.Join(",", values.Select(c => c.ToString())); | ||||
|  | ||||
|             var command = new SQLiteCommand(string.Format("CREATE TABLE [{0}] ({1})", tableName, columns)); | ||||
|             command.Connection = _connection; | ||||
|  | ||||
|             command.ExecuteNonQuery(); | ||||
|         } | ||||
|  | ||||
|         public void CopyData(string sourceTable, string destinationTable, IEnumerable<SQLiteColumn> columns) | ||||
|         { | ||||
|             var originalCount = GetRowCount(sourceTable); | ||||
|  | ||||
|             var columnsToTransfer = String.Join(",", columns.Select(c => c.Name)); | ||||
|  | ||||
|             var transferCommand = BuildCommand("INSERT INTO {0} SELECT {1} FROM {2};", destinationTable, columnsToTransfer, sourceTable); | ||||
|  | ||||
|             transferCommand.ExecuteNonQuery(); | ||||
|  | ||||
|             var transferredRows = GetRowCount(destinationTable); | ||||
|  | ||||
|  | ||||
|             if (transferredRows != originalCount) | ||||
|             { | ||||
|                 throw new ApplicationException(string.Format("Expected {0} rows to be copied from [{1}] to [{2}]. But only copied {3}", originalCount, sourceTable, destinationTable, transferredRows)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         public void DropTable(string tableName) | ||||
|         { | ||||
|             var dropCommand = BuildCommand("DROP TABLE {0};", tableName); | ||||
|             dropCommand.ExecuteNonQuery(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         public void RenameTable(string tableName, string newName) | ||||
|         { | ||||
|             var renameCommand = BuildCommand("ALTER TABLE {0} RENAME TO {1};", tableName, newName); | ||||
|             renameCommand.ExecuteNonQuery(); | ||||
|         } | ||||
|  | ||||
|         public int GetRowCount(string tableName) | ||||
|         { | ||||
|             var countCommand = BuildCommand("SELECT COUNT(*) FROM {0};", tableName); | ||||
|             return Convert.ToInt32(countCommand.ExecuteScalar()); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         public SQLiteTransaction BeginTransaction() | ||||
|         { | ||||
|             return _connection.BeginTransaction(); | ||||
|         } | ||||
|  | ||||
|         private SQLiteCommand BuildCommand(string format, params string[] args) | ||||
|         { | ||||
|             var command = new SQLiteCommand(string.Format(format, args)); | ||||
|             command.Connection = _connection; | ||||
|             return command; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         public class SQLiteColumn | ||||
|         { | ||||
|             public string Name { get; set; } | ||||
|             public string Schema { get; set; } | ||||
|  | ||||
|             public override string ToString() | ||||
|             { | ||||
|                 return string.Format("[{0}] {1}", Name, Schema); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,69 +1,42 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Data.SQLite; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text.RegularExpressions; | ||||
| using FluentMigrator.Builders.Execute; | ||||
|  | ||||
| namespace NzbDrone.Core.Datastore.Migration.Framework | ||||
| { | ||||
|     public class SQLiteAlter | ||||
|     public interface ISQLiteAlter | ||||
|     { | ||||
|         private readonly SQLiteConnection _connection; | ||||
|  | ||||
|         private static readonly Regex SchemaRegex = new Regex(@"[\""\[](?<name>\w+)[\""\]]\s(?<schema>[\w-\s]+)", | ||||
|             RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline); | ||||
|  | ||||
|         public SQLiteAlter(string connectionString) | ||||
|         { | ||||
|             _connection = new SQLiteConnection(connectionString); | ||||
|             _connection.Open(); | ||||
|         } | ||||
|  | ||||
|         private string GetOriginalSql(string tableName) | ||||
|         { | ||||
|             var command = | ||||
|                 new SQLiteCommand(string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name ='{0}'", | ||||
|                                                 tableName)); | ||||
|  | ||||
|             command.Connection = _connection; | ||||
|             return (string)command.ExecuteScalar(); | ||||
|         } | ||||
|  | ||||
|         public Dictionary<String, SQLiteColumn> GetColumns(string tableName) | ||||
|         { | ||||
|             var originalSql = GetOriginalSql(tableName); | ||||
|  | ||||
|             var matches = SchemaRegex.Matches(originalSql); | ||||
|  | ||||
|             return matches.Cast<Match>().ToDictionary( | ||||
|                                match => match.Groups["name"].Value.Trim(), | ||||
|                                match => new SQLiteColumn | ||||
|                                    { | ||||
|                                        Name = match.Groups["name"].Value.Trim(), | ||||
|                                        Schema = match.Groups["schema"].Value.Trim() | ||||
|                                    }); | ||||
|         } | ||||
|  | ||||
|         public void CreateTable(string tableName, Dictionary<string, SQLiteColumn>.ValueCollection values) | ||||
|         { | ||||
|             var columns = String.Join(",", values.Select(c => c.ToString())); | ||||
|  | ||||
|             var command = new SQLiteCommand(string.Format("CREATE TABLE [{0}] ({1})", tableName, columns)); | ||||
|             command.Connection = _connection; | ||||
|  | ||||
|             command.ExecuteNonQuery(); | ||||
|         } | ||||
|         void DropColumns(string tableName, IEnumerable<string> columns); | ||||
|     } | ||||
|  | ||||
|     public class SQLiteColumn | ||||
|     public class SQLiteAlter : ISQLiteAlter | ||||
|     { | ||||
|         public string Name { get; set; } | ||||
|         public string Schema { get; set; } | ||||
|         private readonly ISQLiteMigrationHelper _sqLiteMigrationHelper; | ||||
|  | ||||
|         public override string ToString() | ||||
|         public SQLiteAlter(ISQLiteMigrationHelper sqLiteMigrationHelper) | ||||
|         { | ||||
|             return string.Format("[{0}] {1}", Name, Schema); | ||||
|             _sqLiteMigrationHelper = sqLiteMigrationHelper; | ||||
|         } | ||||
|  | ||||
|         public void DropColumns(string tableName, IEnumerable<string> columns) | ||||
|         { | ||||
|             using (var transaction = _sqLiteMigrationHelper.BeginTransaction()) | ||||
|             { | ||||
|                 var originalColumns = _sqLiteMigrationHelper.GetColumns(tableName); | ||||
|  | ||||
|                 var newColumns = originalColumns.Where(c => !columns.Contains(c.Key)).Select(c => c.Value).ToList(); | ||||
|  | ||||
|                 var tempTableName = tableName + "_temp"; | ||||
|  | ||||
|                 _sqLiteMigrationHelper.CreateTable(tempTableName, newColumns); | ||||
|  | ||||
|                 _sqLiteMigrationHelper.CopyData(tableName, tempTableName, newColumns); | ||||
|  | ||||
|                 _sqLiteMigrationHelper.DropTable(tableName); | ||||
|  | ||||
|                 _sqLiteMigrationHelper.RenameTable(tempTableName, tableName); | ||||
|  | ||||
|                 transaction.Commit(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -194,6 +194,7 @@ | ||||
|     <Compile Include="DataAugmentation\Scene\SceneMappingRepository.cs" /> | ||||
|     <Compile Include="DataAugmentation\Scene\UpdateSceneMappingCommand.cs" /> | ||||
|     <Compile Include="Datastore\CachedBasicRepository.cs" /> | ||||
|     <Compile Include="Datastore\ConnectionStringFactory.cs" /> | ||||
|     <Compile Include="Datastore\Converters\BooleanIntConverter.cs" /> | ||||
|     <Compile Include="Datastore\Converters\QualityIntConverter.cs" /> | ||||
|     <Compile Include="Datastore\Converters\Int32Converter.cs" /> | ||||
| @@ -213,6 +214,7 @@ | ||||
|     <Compile Include="Datastore\Migration\006_add_index_to_log_time.cs" /> | ||||
|     <Compile Include="Datastore\Migration\007_add_renameEpisodes_to_naming.cs" /> | ||||
|     <Compile Include="Datastore\Migration\007_remove_backlog.cs" /> | ||||
|     <Compile Include="Datastore\Migration\Framework\MigrationContext.cs" /> | ||||
|     <Compile Include="Datastore\Migration\Framework\MigrationController.cs" /> | ||||
|     <Compile Include="Datastore\Migration\Framework\MigrationExtension.cs" /> | ||||
|     <Compile Include="Datastore\Migration\Framework\MigrationOptions.cs" /> | ||||
| @@ -220,7 +222,8 @@ | ||||
|     <Compile Include="Datastore\Migration\001_initialSetup.cs" /> | ||||
|     <Compile Include="Datastore\Migration\Framework\NzbDroneMigrationBase.cs" /> | ||||
|     <Compile Include="Datastore\MigrationType.cs" /> | ||||
|     <Compile Include="Datastore\Migration\Framework\SqliteAlter.cs" /> | ||||
|     <Compile Include="Datastore\Migration\Framework\SQLiteAlter.cs" /> | ||||
|     <Compile Include="Datastore\Migration\Framework\SQLiteMigrationHelper.cs" /> | ||||
|     <Compile Include="Datastore\ModelBase.cs" /> | ||||
|     <Compile Include="Datastore\BasicRepository.cs" /> | ||||
|     <Compile Include="Datastore\PagingSpec.cs" /> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user