using Comal.Stores; using InABox.Configuration; using InABox.Core; using InABox.Database; using InABox.Database.SQLite; using InABox.Logging; using InABox.Wpf; using InABox.WPF; using PRSServices; using System; using System.Collections.Generic; using System.Data.Common; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PRSServer.Forms.Version9Update; public static class UpdateDatabaseFiles { public static bool UpdateDatabases(int targetMajorVersion) { try { Progress.ShowModal("Loading Data", progress => { var sections = PRSService.GetConfiguration().LoadAll(); var stores = CoreUtils.TypeList( AppDomain.CurrentDomain.GetAssemblies(), myType => myType.IsClass && !myType.IsAbstract && !myType.IsGenericType && myType.GetInterfaces().Contains(typeof(IStore)) ).ToArray(); foreach (var section in sections.Where(x => x.Value.Type == ServerType.Database)) { var properties = section.Value.DeserializeServerProperties(); if (properties is not DatabaseServerProperties databaseProperties) continue; var factory = new SQLiteProviderFactory(databaseProperties.FileName); // Not starting the factory, since otherwise that will do bad things to the database if it is already version 9. // Instead, we just want to call a single SQL statement, really. var originalVersion = DbFactory.GetDatabaseVersion(factory); if (originalVersion.MajorVersion >= targetMajorVersion) continue; progress.Report($"Backing up database '{databaseProperties.Name}'"); if (File.Exists(databaseProperties.FileName)) { var directory = Path.GetDirectoryName(databaseProperties.FileName) ?? ""; var originalFileName = Path.GetFileNameWithoutExtension(databaseProperties.FileName); var newFileName = Path.Combine(directory, $"{originalFileName}_{originalVersion}_backup.dbs"); var i = 0; while (File.Exists(newFileName)) { newFileName = Path.Combine(directory, $"{originalFileName}_{originalVersion}_backup_{i}.dbs"); ++i; } File.Copy(databaseProperties.FileName, newFileName); } progress.Report($"Updating database '{databaseProperties.Name}' from version {originalVersion}"); DbFactory.Stores = stores; DbFactory.DefaultStore = typeof(BaseStore<>); // Adding extra logger so that the SQL transactions are put in the right place. var logger = new LogFileLogger(DatabaseEngine.GetPath(section.Key), true); MainLogger.AddLogger(logger); factory = new SQLiteProviderFactory(databaseProperties.FileName); factory.Types = DbFactory.Entities.Where(x => x.IsClass && !x.IsGenericType && x.IsSubclassOf(typeof(Entity)) ).ToArray(); DbFactory.ProviderFactory = factory; DbFactory.Start(); // Doing this will run all the update scripts. factory.InitializeNulls(); var dbVersion = DbFactory.GetVersionSettings(factory); dbVersion.Version = new VersionNumber(9, 0).ToString(); var result = factory.NewProvider(Logger.Main) .Query(Filter.Where(x => x.Section).IsEqualTo(nameof(DatabaseVersion))) .Rows.FirstOrDefault()?.ToObject() ?? new GlobalSettings() { Section = nameof(DatabaseVersion), Key = "" }; result.OriginalValueList["Contents"] = result.Contents; result.Contents = Serialization.Serialize(dbVersion); factory.NewProvider(Logger.Main).Save(result); MainLogger.RemoveLogger(logger); } }); return true; } catch(Exception e) { MessageWindow.ShowError($"An error occurred while updating database files.", e); return false; } } }