From 4bae9e89cf151b7008a52ef29b2ec890352f117d Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 10 Mar 2024 21:18:20 +0100 Subject: [PATCH] Storage - Clean up legacy project and refactor repositories to use short lived DB contexts --- src/Artemis.Core/Artemis.Core.csproj | 2 +- src/Artemis.Core/Constants.cs | 2 +- src/Artemis.Core/Plugins/Plugin.cs | 8 +- .../Plugins/Settings/PluginSetting.cs | 2 +- .../Plugins/Settings/PluginSettings.cs | 7 +- src/Artemis.Core/Services/DeviceService.cs | 8 +- .../Services/PluginManagementService.cs | 8 +- src/Artemis.Core/Services/SettingsService.cs | 2 +- .../Storage/Interfaces/IProfileService.cs | 8 +- .../Services/Storage/ProfileService.cs | 70 ++------ .../Artemis.Storage.Legacy.csproj} | 5 +- .../Entities/General/QueuedActionEntity.cs | 4 +- .../Entities/General/ReleaseEntity.cs | 4 +- .../General/ScriptConfigurationEntity.cs | 4 +- .../Entities/Plugins/PluginEntity.cs | 8 +- .../Entities/Plugins/PluginSettingEntity.cs | 4 +- .../Profile/Abstract/RenderElementEntity.cs | 6 +- .../CategoryAdaptionHintEntity.cs | 4 +- .../AdaptionHints/DeviceAdaptionHintEntity.cs | 4 +- .../AdaptionHints/IAdaptionHintEntity.cs | 2 +- .../KeyboardSectionAdaptionHintEntity.cs | 6 + .../SingleLedAdaptionHintEntity.cs | 4 +- .../Conditions/AlwaysOnConditionEntity.cs | 3 + .../Conditions/EventConditionEntity.cs | 6 +- .../Profile/Conditions/IConditionEntity.cs | 2 +- .../Conditions/PlayOnceConditionEntity.cs | 3 + .../Conditions/StaticConditionEntity.cs | 10 ++ .../Profile/DataBindings/DataBindingEntity.cs | 9 + .../Entities/Profile/DataModelPathEntity.cs | 4 +- .../Entities/Profile/FolderEntity.cs | 6 +- .../Entities/Profile/KeyframeEntity.cs | 4 +- .../Entities/Profile/LayerBrushEntity.cs | 4 +- .../Entities/Profile/LayerEffectEntity.cs | 4 +- .../Entities/Profile/LayerEntity.cs | 8 +- .../Entities/Profile/LedEntity.cs | 4 +- .../Profile/Nodes/NodeConnectionEntity.cs | 4 +- .../Entities/Profile/Nodes/NodeEntity.cs | 4 +- .../Profile/Nodes/NodePinCollectionEntity.cs | 4 +- .../Profile/Nodes/NodeScriptEntity.cs | 4 +- .../Entities/Profile/ProfileCategoryEntity.cs | 4 +- .../Profile/ProfileConfigurationEntity.cs | 6 +- .../ProfileConfigurationHotkeyEntity.cs | 7 + .../Entities/Profile/ProfileEntity.cs | 6 +- .../Entities/Profile/PropertyEntity.cs | 6 +- .../Entities/Profile/PropertyGroupEntity.cs | 4 +- .../Entities/Profile/TimelineEntity.cs | 4 +- .../Entities/Surface/DeviceEntity.cs | 8 +- .../Entities/Workshop/EntryEntity.cs | 4 +- .../LegacyMigrationService.cs | 163 ++++++++++++++++++ .../Migrations/IProfileMigration.cs | 2 +- .../Migrations/IStorageMigration.cs | 2 +- .../Migrations/Storage/M0020AvaloniaReset.cs | 4 +- .../Migrations/Storage/M0021GradientNodes.cs | 10 +- .../Storage/M0022TransitionNodes.cs | 10 +- .../Storage/M0023LayoutProviders.cs | 8 +- .../Migrations/Storage/M0024NodeProviders.cs | 21 +-- .../M0025NodeProvidersProfileConfig.cs | 9 +- .../Migrations/Storage/M0026NodeStorage.cs | 16 +- .../Migrations/Storage/M0027Namespace.cs | 12 +- src/Artemis.Storage.Legacy/Program.cs | 22 +++ .../KeyboardSectionAdaptionHintEntity.cs | 6 - .../Conditions/AlwaysOnConditionEntity.cs | 3 - .../Conditions/PlayOnceConditionEntity.cs | 3 - .../Conditions/StaticConditionEntity.cs | 10 -- .../Profile/DataBindings/DataBindingEntity.cs | 9 - .../ProfileConfigurationHotkeyEntity.cs | 7 - .../Legacy/StorageMigrationService.cs | 34 ---- src/Artemis.Storage.Migrator/Program.cs | 142 --------------- src/Artemis.Storage.Migrator/artemis.db | Bin 86016 -> 0 bytes src/Artemis.Storage/ArtemisDbContext.cs | 2 + .../Entities/General/ReleaseEntity.cs | 6 + .../Entities/Plugins/PluginEntity.cs | 6 +- .../Entities/Plugins/PluginSettingEntity.cs | 5 + .../Entities/Profile/ProfileCategoryEntity.cs | 4 + .../Entities/RawProfileContainer.cs | 10 ++ .../Entities/Surface/DeviceEntity.cs | 13 +- .../Entities/Workshop/EntryEntity.cs | 11 +- .../Exceptions/ArtemisStorageException.cs | 14 ++ ....cs => 20240310201706_Initial.Designer.cs} | 37 +++- ...1_Initial.cs => 20240310201706_Initial.cs} | 83 ++++++--- .../ArtemisDbContextModelSnapshot.cs | 35 +++- .../Repositories/DeviceRepository.cs | 43 +++-- .../Repositories/EntryRepository.cs | 36 ++-- .../Interfaces/IDeviceRepository.cs | 3 +- .../Interfaces/IEntryRepository.cs | 2 +- .../Interfaces/IPluginRepository.cs | 7 +- .../Interfaces/IProfileCategoryRepository.cs | 3 +- .../Interfaces/IProfileRepository.cs | 15 ++ .../Interfaces/IReleaseRepository.cs | 9 + .../Repositories/PluginRepository.cs | 49 +++--- .../Repositories/ProfileCategoryRepository.cs | 58 ++++--- .../Repositories/ProfileRepository.cs | 91 ++++++++++ .../Repositories/ReleaseRepository.cs | 26 +-- src/Artemis.UI.Linux/App.axaml.cs | 4 + src/Artemis.UI.Linux/Artemis.UI.Linux.csproj | 1 + src/Artemis.UI.MacOS/App.axaml.cs | 4 + src/Artemis.UI.MacOS/Artemis.UI.MacOS.csproj | 1 + .../Artemis.UI.Shared.csproj | 1 + src/Artemis.UI.Windows/App.axaml.cs | 4 + .../Artemis.UI.Windows.csproj | 1 + .../Services/Updating/UpdateService.cs | 1 + .../ProfileEntryInstallationHandler.cs | 2 +- .../Services/WorkshopService.cs | 7 +- src/Artemis.sln | 2 +- src/Directory.Packages.props | 3 +- 105 files changed, 818 insertions(+), 578 deletions(-) rename src/{Artemis.Storage.Migrator/Artemis.Storage.Migrator.csproj => Artemis.Storage.Legacy/Artemis.Storage.Legacy.csproj} (78%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/General/QueuedActionEntity.cs (76%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/General/ReleaseEntity.cs (82%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/General/ScriptConfigurationEntity.cs (66%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Plugins/PluginEntity.cs (88%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Plugins/PluginSettingEntity.cs (85%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/Abstract/RenderElementEntity.cs (58%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/AdaptionHints/CategoryAdaptionHintEntity.cs (52%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/AdaptionHints/DeviceAdaptionHintEntity.cs (53%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs (82%) create mode 100644 src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/KeyboardSectionAdaptionHintEntity.cs rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/AdaptionHints/SingleLedAdaptionHintEntity.cs (52%) create mode 100644 src/Artemis.Storage.Legacy/Entities/Profile/Conditions/AlwaysOnConditionEntity.cs rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/Conditions/EventConditionEntity.cs (55%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/Conditions/IConditionEntity.cs (81%) create mode 100644 src/Artemis.Storage.Legacy/Entities/Profile/Conditions/PlayOnceConditionEntity.cs create mode 100644 src/Artemis.Storage.Legacy/Entities/Profile/Conditions/StaticConditionEntity.cs create mode 100644 src/Artemis.Storage.Legacy/Entities/Profile/DataBindings/DataBindingEntity.cs rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/DataModelPathEntity.cs (59%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/FolderEntity.cs (63%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/KeyframeEntity.cs (66%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/LayerBrushEntity.cs (66%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/LayerEffectEntity.cs (77%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/LayerEntity.cs (73%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/LedEntity.cs (92%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/Nodes/NodeConnectionEntity.cs (90%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/Nodes/NodeEntity.cs (92%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/Nodes/NodePinCollectionEntity.cs (79%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/Nodes/NodeScriptEntity.cs (78%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/ProfileCategoryEntity.cs (96%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/ProfileConfigurationEntity.cs (83%) create mode 100644 src/Artemis.Storage.Legacy/Entities/Profile/ProfileConfigurationHotkeyEntity.cs rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/ProfileEntity.cs (84%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/PropertyEntity.cs (64%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/PropertyGroupEntity.cs (68%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Profile/TimelineEntity.cs (63%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Surface/DeviceEntity.cs (93%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Entities/Workshop/EntryEntity.cs (91%) create mode 100644 src/Artemis.Storage.Legacy/LegacyMigrationService.cs rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/IProfileMigration.cs (75%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/IStorageMigration.cs (70%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/Storage/M0020AvaloniaReset.cs (76%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/Storage/M0021GradientNodes.cs (92%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/Storage/M0022TransitionNodes.cs (91%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/Storage/M0023LayoutProviders.cs (88%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/Storage/M0024NodeProviders.cs (93%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/Storage/M0025NodeProvidersProfileConfig.cs (91%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/Storage/M0026NodeStorage.cs (97%) rename src/{Artemis.Storage.Migrator/Legacy => Artemis.Storage.Legacy}/Migrations/Storage/M0027Namespace.cs (79%) create mode 100644 src/Artemis.Storage.Legacy/Program.cs delete mode 100644 src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/KeyboardSectionAdaptionHintEntity.cs delete mode 100644 src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/AlwaysOnConditionEntity.cs delete mode 100644 src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/PlayOnceConditionEntity.cs delete mode 100644 src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/StaticConditionEntity.cs delete mode 100644 src/Artemis.Storage.Migrator/Legacy/Entities/Profile/DataBindings/DataBindingEntity.cs delete mode 100644 src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileConfigurationHotkeyEntity.cs delete mode 100644 src/Artemis.Storage.Migrator/Legacy/StorageMigrationService.cs delete mode 100644 src/Artemis.Storage.Migrator/Program.cs delete mode 100644 src/Artemis.Storage.Migrator/artemis.db create mode 100644 src/Artemis.Storage/Entities/RawProfileContainer.cs create mode 100644 src/Artemis.Storage/Exceptions/ArtemisStorageException.cs rename src/Artemis.Storage/Migrations/{20240308203921_Initial.Designer.cs => 20240310201706_Initial.Designer.cs} (90%) rename src/Artemis.Storage/Migrations/{20240308203921_Initial.cs => 20240310201706_Initial.cs} (74%) create mode 100644 src/Artemis.Storage/Repositories/Interfaces/IProfileRepository.cs create mode 100644 src/Artemis.Storage/Repositories/Interfaces/IReleaseRepository.cs create mode 100644 src/Artemis.Storage/Repositories/ProfileRepository.cs diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index 75fa9a3a1..42daefc59 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -40,7 +40,7 @@ - + diff --git a/src/Artemis.Core/Constants.cs b/src/Artemis.Core/Constants.cs index 79d19cc48..dfa7791c5 100644 --- a/src/Artemis.Core/Constants.cs +++ b/src/Artemis.Core/Constants.cs @@ -91,7 +91,7 @@ public static class Constants /// /// The plugin used by core components of Artemis /// - public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), new PluginEntity(){Id = CorePluginInfo.Guid}, false); + public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), new PluginEntity(){PluginGuid = CorePluginInfo.Guid}, false); /// /// A read-only collection containing all primitive numeric types diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs index 2b5ce51d1..5eacf18f0 100644 --- a/src/Artemis.Core/Plugins/Plugin.cs +++ b/src/Artemis.Core/Plugins/Plugin.cs @@ -309,13 +309,7 @@ public class Plugin : CorePropertyChanged, IDisposable { FeatureRemoved?.Invoke(this, e); } - - internal void ApplyToEntity() - { - Entity.Id = Guid; - Entity.IsEnabled = IsEnabled; - } - + internal void AddFeature(PluginFeatureInfo featureInfo) { if (featureInfo.Plugin != this) diff --git a/src/Artemis.Core/Plugins/Settings/PluginSetting.cs b/src/Artemis.Core/Plugins/Settings/PluginSetting.cs index e3510a58e..8f14d542f 100644 --- a/src/Artemis.Core/Plugins/Settings/PluginSetting.cs +++ b/src/Artemis.Core/Plugins/Settings/PluginSetting.cs @@ -94,7 +94,7 @@ public class PluginSetting : CorePropertyChanged, IPluginSetting return; _pluginSettingEntity.Value = CoreJson.Serialize(Value); - _pluginRepository.SaveChanges(); + _pluginRepository.SaveSetting(_pluginSettingEntity); OnSettingSaved(); } diff --git a/src/Artemis.Core/Plugins/Settings/PluginSettings.cs b/src/Artemis.Core/Plugins/Settings/PluginSettings.cs index 89c1a10ea..811dcf817 100644 --- a/src/Artemis.Core/Plugins/Settings/PluginSettings.cs +++ b/src/Artemis.Core/Plugins/Settings/PluginSettings.cs @@ -31,10 +31,13 @@ public class PluginSettings /// Gets the setting with the provided name. If the setting does not exist yet, it is created. /// /// The type of the setting, can be any serializable type - /// The name of the setting + /// The name of the setting, may not be longer than 128 characters /// The default value to use if the setting does not exist yet public PluginSetting GetSetting(string name, T? defaultValue = default) { + if (name.Length > 128) + throw new ArtemisCoreException("Setting name cannot be longer than 128 characters"); + lock (_settingEntities) { // Return cached value if available @@ -51,7 +54,7 @@ public class PluginSettings PluginGuid = Plugin.Guid, Value = CoreJson.Serialize(defaultValue) }; - _pluginRepository.AddSetting(settingEntity); + _pluginRepository.SaveSetting(settingEntity); } PluginSetting pluginSetting = new(_pluginRepository, settingEntity); diff --git a/src/Artemis.Core/Services/DeviceService.cs b/src/Artemis.Core/Services/DeviceService.cs index 46399722e..da81a82a6 100644 --- a/src/Artemis.Core/Services/DeviceService.cs +++ b/src/Artemis.Core/Services/DeviceService.cs @@ -202,7 +202,7 @@ internal class DeviceService : IDeviceService _enabledDevices.Add(device); device.IsEnabled = true; device.Save(); - _deviceRepository.SaveChanges(); + _deviceRepository.Save(device.DeviceEntity); OnDeviceEnabled(new DeviceEventArgs(device)); UpdateLeds(); @@ -217,7 +217,7 @@ internal class DeviceService : IDeviceService _enabledDevices.Remove(device); device.IsEnabled = false; device.Save(); - _deviceRepository.SaveChanges(); + _deviceRepository.Save(device.DeviceEntity); OnDeviceDisabled(new DeviceEventArgs(device)); UpdateLeds(); @@ -227,7 +227,7 @@ internal class DeviceService : IDeviceService public void SaveDevice(ArtemisDevice artemisDevice) { artemisDevice.Save(); - _deviceRepository.SaveChanges(); + _deviceRepository.Save(artemisDevice.DeviceEntity); UpdateLeds(); } @@ -236,7 +236,7 @@ internal class DeviceService : IDeviceService { foreach (ArtemisDevice artemisDevice in _devices) artemisDevice.Save(); - _deviceRepository.SaveChanges(); + _deviceRepository.SaveRange(_devices.Select(d => d.DeviceEntity)); UpdateLeds(); } diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index 5b31b31d9..62bc658ac 100644 --- a/src/Artemis.Core/Services/PluginManagementService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -372,12 +372,12 @@ internal class PluginManagementService : IPluginManagementService } // Load the entity and fall back on creating a new one - PluginEntity? entity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid); + PluginEntity? entity = _pluginRepository.GetPluginByPluginGuid(pluginInfo.Guid); bool loadedFromStorage = entity != null; if (entity == null) { - entity = new PluginEntity {Id = pluginInfo.Guid}; - _pluginRepository.AddPlugin(entity); + entity = new PluginEntity {PluginGuid = pluginInfo.Guid}; + _pluginRepository.SavePlugin(entity); } Plugin plugin = new(pluginInfo, directory, entity, loadedFromStorage); @@ -815,7 +815,7 @@ internal class PluginManagementService : IPluginManagementService plugin.Entity.Features.Add(featureInfo.Instance!.Entity); } - _pluginRepository.SaveChanges(); + _pluginRepository.SavePlugin(plugin.Entity); } #endregion diff --git a/src/Artemis.Core/Services/SettingsService.cs b/src/Artemis.Core/Services/SettingsService.cs index 96719eae0..a3cf4c030 100644 --- a/src/Artemis.Core/Services/SettingsService.cs +++ b/src/Artemis.Core/Services/SettingsService.cs @@ -34,7 +34,7 @@ public interface ISettingsService : IProtectedArtemisService /// Gets the setting with the provided name. If the setting does not exist yet, it is created. /// /// The type of the setting, can be any serializable type - /// The name of the setting + /// The name of the setting, may not be longer than 128 characters /// The default value to use if the setting does not exist yet /// PluginSetting GetSetting(string name, T? defaultValue = default); diff --git a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs index 47766f5bb..c8a5f8435 100644 --- a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs +++ b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs @@ -54,13 +54,7 @@ public interface IProfileService : IArtemisService /// /// The profile configuration of the profile to activate. void DeactivateProfile(ProfileConfiguration profileConfiguration); - - /// - /// Permanently deletes the profile of the given . - /// - /// The profile configuration of the profile to delete. - void DeleteProfile(ProfileConfiguration profileConfiguration); - + /// /// Saves the provided and it's s but not the /// s themselves. diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index 423f50797..6b9889e19 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -22,6 +22,7 @@ internal class ProfileService : IProfileService { private readonly ILogger _logger; private readonly IProfileCategoryRepository _profileCategoryRepository; + private readonly IProfileRepository _profileRepository; private readonly IPluginManagementService _pluginManagementService; private readonly IDeviceService _deviceService; private readonly List _pendingKeyboardEvents = new(); @@ -34,6 +35,7 @@ internal class ProfileService : IProfileService public ProfileService(ILogger logger, IProfileCategoryRepository profileCategoryRepository, + IProfileRepository profileRepository, IPluginManagementService pluginManagementService, IInputService inputService, IDeviceService deviceService, @@ -41,6 +43,7 @@ internal class ProfileService : IProfileService { _logger = logger; _profileCategoryRepository = profileCategoryRepository; + _profileRepository = profileRepository; _pluginManagementService = pluginManagementService; _deviceService = deviceService; _profileMigrators = profileMigrators; @@ -214,20 +217,7 @@ internal class ProfileService : IProfileService profileConfiguration.Profile.ShouldDisplay = false; } - - /// - public void DeleteProfile(ProfileConfiguration profileConfiguration) - { - DeactivateProfile(profileConfiguration); - - ProfileCategory category = profileConfiguration.Category; - - category.RemoveProfileConfiguration(profileConfiguration); - category.Entity.ProfileConfigurations.Remove(profileConfiguration.Entity); - - _profileCategoryRepository.SaveChanges(); - } - + /// public ProfileCategory CreateProfileCategory(string name, bool addToTop = false) { @@ -240,6 +230,8 @@ internal class ProfileService : IProfileService category.Order++; category.Save(); } + + _profileCategoryRepository.SaveRange(ProfileCategories.Select(c => c.Entity).ToList()); } else { @@ -274,32 +266,32 @@ internal class ProfileService : IProfileService SaveProfileCategory(category); return configuration; } - + /// public void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration) { - ProfileCategory category = profileConfiguration.Category; - category.RemoveProfileConfiguration(profileConfiguration); - DeactivateProfile(profileConfiguration); - SaveProfileCategory(profileConfiguration.Category); - profileConfiguration.Dispose(); + ProfileCategory category = profileConfiguration.Category; + + category.RemoveProfileConfiguration(profileConfiguration); + category.Save(); + + _profileRepository.Remove(profileConfiguration.Entity); + _profileCategoryRepository.Save(category.Entity); } /// public void SaveProfileCategory(ProfileCategory profileCategory) { profileCategory.Save(); - _profileCategoryRepository.SaveChanges(); + _profileCategoryRepository.Save(profileCategory.Entity); ProfileCategories = new ReadOnlyCollection(ProfileCategories.OrderBy(c => c.Order).ToList()); } /// public void SaveProfile(Profile profile, bool includeChildren) { - Stopwatch sw = new(); - sw.Start(); _logger.Debug("Updating profile - Saving {Profile}", profile); profile.Save(); if (includeChildren) @@ -312,7 +304,7 @@ internal class ProfileService : IProfileService profile.IsFreshImport = false; profile.ProfileEntity.IsFreshImport = false; - SaveProfileCategory(profile.Configuration.Category); + _profileRepository.Save(profile.Configuration.Entity); // If the provided profile is external (cloned or from the workshop?) but it is loaded locally too, reload the local instance // A bit dodge but it ensures local instances always represent the latest stored version @@ -320,17 +312,10 @@ internal class ProfileService : IProfileService .SelectMany(c => c.ProfileConfigurations) .FirstOrDefault(p => p.Profile != null && p.Profile != profile && p.ProfileId == profile.ProfileEntity.Id); if (localInstance == null) - { - sw.Stop(); - _logger.Debug("Updated profile - Saved {Profile} in {Time}ms", profile, sw.Elapsed.TotalMilliseconds); return; - } DeactivateProfile(localInstance); ActivateProfile(localInstance); - - sw.Stop(); - _logger.Debug("Updated profile - Saved {Profile} in {Time}ms", profile, sw.Elapsed.TotalMilliseconds); } /// @@ -393,7 +378,7 @@ internal class ProfileService : IProfileService JsonObject? profileJson = CoreJson.Deserialize(await profileReader.ReadToEndAsync()); // Before deserializing, apply any pending migrations - MigrateProfile(configurationJson, profileJson); + _profileRepository.MigrateProfile(configurationJson, profileJson); // Deserialize profile configuration to ProfileConfigurationEntity ProfileConfigurationEntity? configurationEntity = configurationJson?.Deserialize(Constants.JsonConvertSettings); @@ -453,7 +438,7 @@ internal class ProfileService : IProfileService { ProfileConfiguration imported = await ImportProfile(archiveStream, profileConfiguration.Category, true, true, null, profileConfiguration.Order + 1); - DeleteProfile(profileConfiguration); + RemoveProfileConfiguration(profileConfiguration); SaveProfileCategory(imported.Category); return imported; @@ -479,24 +464,7 @@ internal class ProfileService : IProfileService { _pendingKeyboardEvents.Add(e); } - - private void MigrateProfile(JsonObject? configurationJson, JsonObject? profileJson) - { - if (configurationJson == null || profileJson == null) - return; - - configurationJson["Version"] ??= 0; - - foreach (IProfileMigration profileMigrator in _profileMigrators.OrderBy(m => m.Version)) - { - if (profileMigrator.Version <= configurationJson["Version"]!.GetValue()) - continue; - - profileMigrator.Migrate(configurationJson, profileJson); - configurationJson["Version"] = profileMigrator.Version; - } - } - + /// /// Populates all missing LEDs on all currently active profiles /// diff --git a/src/Artemis.Storage.Migrator/Artemis.Storage.Migrator.csproj b/src/Artemis.Storage.Legacy/Artemis.Storage.Legacy.csproj similarity index 78% rename from src/Artemis.Storage.Migrator/Artemis.Storage.Migrator.csproj rename to src/Artemis.Storage.Legacy/Artemis.Storage.Legacy.csproj index dbc3a660d..2da8bd8c3 100644 --- a/src/Artemis.Storage.Migrator/Artemis.Storage.Migrator.csproj +++ b/src/Artemis.Storage.Legacy/Artemis.Storage.Legacy.csproj @@ -1,7 +1,6 @@  - Exe net8.0 enable enable @@ -13,8 +12,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/General/QueuedActionEntity.cs b/src/Artemis.Storage.Legacy/Entities/General/QueuedActionEntity.cs similarity index 76% rename from src/Artemis.Storage.Migrator/Legacy/Entities/General/QueuedActionEntity.cs rename to src/Artemis.Storage.Legacy/Entities/General/QueuedActionEntity.cs index 8244c57ec..90770d565 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/General/QueuedActionEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/General/QueuedActionEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.General; +namespace Artemis.Storage.Legacy.Entities.General; -public class QueuedActionEntity +internal class QueuedActionEntity { public QueuedActionEntity() { diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/General/ReleaseEntity.cs b/src/Artemis.Storage.Legacy/Entities/General/ReleaseEntity.cs similarity index 82% rename from src/Artemis.Storage.Migrator/Legacy/Entities/General/ReleaseEntity.cs rename to src/Artemis.Storage.Legacy/Entities/General/ReleaseEntity.cs index a0d9795bf..a8aea26a8 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/General/ReleaseEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/General/ReleaseEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.General; +namespace Artemis.Storage.Legacy.Entities.General; -public class ReleaseEntity +internal class ReleaseEntity { public Guid Id { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/General/ScriptConfigurationEntity.cs b/src/Artemis.Storage.Legacy/Entities/General/ScriptConfigurationEntity.cs similarity index 66% rename from src/Artemis.Storage.Migrator/Legacy/Entities/General/ScriptConfigurationEntity.cs rename to src/Artemis.Storage.Legacy/Entities/General/ScriptConfigurationEntity.cs index 4c1743fb6..94fce07e4 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/General/ScriptConfigurationEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/General/ScriptConfigurationEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.General; +namespace Artemis.Storage.Legacy.Entities.General; -public class ScriptConfigurationEntity +internal class ScriptConfigurationEntity { public Guid Id { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Plugins/PluginEntity.cs b/src/Artemis.Storage.Legacy/Entities/Plugins/PluginEntity.cs similarity index 88% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Plugins/PluginEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Plugins/PluginEntity.cs index 779b42fff..47e2ba74b 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Plugins/PluginEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Plugins/PluginEntity.cs @@ -1,9 +1,9 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Plugins; +namespace Artemis.Storage.Legacy.Entities.Plugins; /// /// Represents the configuration of a plugin, each plugin has one configuration /// -public class PluginEntity +internal class PluginEntity { public PluginEntity() { @@ -19,7 +19,7 @@ public class PluginEntity { return new Artemis.Storage.Entities.Plugins.PluginEntity() { - Id = Id, + PluginGuid = Id, IsEnabled = IsEnabled, Features = Features.Select(f => f.Migrate()).ToList() }; @@ -29,7 +29,7 @@ public class PluginEntity /// /// Represents the configuration of a plugin feature, each feature has one configuration /// -public class PluginFeatureEntity +internal class PluginFeatureEntity { public string Type { get; set; } = string.Empty; public bool IsEnabled { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Plugins/PluginSettingEntity.cs b/src/Artemis.Storage.Legacy/Entities/Plugins/PluginSettingEntity.cs similarity index 85% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Plugins/PluginSettingEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Plugins/PluginSettingEntity.cs index 2d10b80e2..587e7d1c8 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Plugins/PluginSettingEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Plugins/PluginSettingEntity.cs @@ -1,9 +1,9 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Plugins; +namespace Artemis.Storage.Legacy.Entities.Plugins; /// /// Represents the setting of a plugin, a plugin can have multiple settings /// -public class PluginSettingEntity +internal class PluginSettingEntity { public Guid Id { get; set; } public Guid PluginGuid { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Abstract/RenderElementEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Abstract/RenderElementEntity.cs similarity index 58% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Abstract/RenderElementEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/Abstract/RenderElementEntity.cs index 98f01a41e..56b4e97fd 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Abstract/RenderElementEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Abstract/RenderElementEntity.cs @@ -1,8 +1,8 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions; +using Artemis.Storage.Legacy.Entities.Profile.Conditions; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Abstract; +namespace Artemis.Storage.Legacy.Entities.Profile.Abstract; -public abstract class RenderElementEntity +internal abstract class RenderElementEntity { public Guid Id { get; set; } public Guid ParentId { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/CategoryAdaptionHintEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/CategoryAdaptionHintEntity.cs similarity index 52% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/CategoryAdaptionHintEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/CategoryAdaptionHintEntity.cs index 3576c5cde..16ceb4d79 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/CategoryAdaptionHintEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/CategoryAdaptionHintEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints; +namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints; -public class CategoryAdaptionHintEntity : IAdaptionHintEntity +internal class CategoryAdaptionHintEntity : IAdaptionHintEntity { public int Category { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/DeviceAdaptionHintEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/DeviceAdaptionHintEntity.cs similarity index 53% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/DeviceAdaptionHintEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/DeviceAdaptionHintEntity.cs index f7a078867..dc4005707 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/DeviceAdaptionHintEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/DeviceAdaptionHintEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints; +namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints; -public class DeviceAdaptionHintEntity : IAdaptionHintEntity +internal class DeviceAdaptionHintEntity : IAdaptionHintEntity { public int DeviceType { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs similarity index 82% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs index 9ff03f4bd..a18f3b6ac 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/IAdaptionHintEntity.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints; +namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints; [JsonDerivedType(typeof(CategoryAdaptionHintEntity), "Category")] [JsonDerivedType(typeof(DeviceAdaptionHintEntity), "Device")] diff --git a/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/KeyboardSectionAdaptionHintEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/KeyboardSectionAdaptionHintEntity.cs new file mode 100644 index 000000000..4d67359c6 --- /dev/null +++ b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/KeyboardSectionAdaptionHintEntity.cs @@ -0,0 +1,6 @@ +namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints; + +internal class KeyboardSectionAdaptionHintEntity : IAdaptionHintEntity +{ + public int Section { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/SingleLedAdaptionHintEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/SingleLedAdaptionHintEntity.cs similarity index 52% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/SingleLedAdaptionHintEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/SingleLedAdaptionHintEntity.cs index 98d192595..9d03535d3 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/SingleLedAdaptionHintEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/AdaptionHints/SingleLedAdaptionHintEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints; +namespace Artemis.Storage.Legacy.Entities.Profile.AdaptionHints; -public class SingleLedAdaptionHintEntity : IAdaptionHintEntity +internal class SingleLedAdaptionHintEntity : IAdaptionHintEntity { public int LedId { get; set; } diff --git a/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/AlwaysOnConditionEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/AlwaysOnConditionEntity.cs new file mode 100644 index 000000000..498d97885 --- /dev/null +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/AlwaysOnConditionEntity.cs @@ -0,0 +1,3 @@ +namespace Artemis.Storage.Legacy.Entities.Profile.Conditions; + +internal class AlwaysOnConditionEntity : IConditionEntity; \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/EventConditionEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/EventConditionEntity.cs similarity index 55% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/EventConditionEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/Conditions/EventConditionEntity.cs index 2fea241b0..574d5d42e 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/EventConditionEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/EventConditionEntity.cs @@ -1,8 +1,8 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; +using Artemis.Storage.Legacy.Entities.Profile.Nodes; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions; +namespace Artemis.Storage.Legacy.Entities.Profile.Conditions; -public class EventConditionEntity : IConditionEntity +internal class EventConditionEntity : IConditionEntity { public int TriggerMode { get; set; } public int OverlapMode { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/IConditionEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/IConditionEntity.cs similarity index 81% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/IConditionEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/Conditions/IConditionEntity.cs index bc78042aa..ab5086aa9 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/IConditionEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/IConditionEntity.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions; +namespace Artemis.Storage.Legacy.Entities.Profile.Conditions; [JsonDerivedType(typeof(AlwaysOnConditionEntity), "AlwaysOn")] [JsonDerivedType(typeof(EventConditionEntity), "Event")] diff --git a/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/PlayOnceConditionEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/PlayOnceConditionEntity.cs new file mode 100644 index 000000000..798ef08c2 --- /dev/null +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/PlayOnceConditionEntity.cs @@ -0,0 +1,3 @@ +namespace Artemis.Storage.Legacy.Entities.Profile.Conditions; + +internal class PlayOnceConditionEntity : IConditionEntity; \ No newline at end of file diff --git a/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/StaticConditionEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/StaticConditionEntity.cs new file mode 100644 index 000000000..a4bfcc06b --- /dev/null +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Conditions/StaticConditionEntity.cs @@ -0,0 +1,10 @@ +using Artemis.Storage.Legacy.Entities.Profile.Nodes; + +namespace Artemis.Storage.Legacy.Entities.Profile.Conditions; + +internal class StaticConditionEntity : IConditionEntity +{ + public int PlayMode { get; set; } + public int StopMode { get; set; } + public NodeScriptEntity? Script { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.Storage.Legacy/Entities/Profile/DataBindings/DataBindingEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/DataBindings/DataBindingEntity.cs new file mode 100644 index 000000000..39be84d72 --- /dev/null +++ b/src/Artemis.Storage.Legacy/Entities/Profile/DataBindings/DataBindingEntity.cs @@ -0,0 +1,9 @@ +using Artemis.Storage.Legacy.Entities.Profile.Nodes; + +namespace Artemis.Storage.Legacy.Entities.Profile.DataBindings; + +internal class DataBindingEntity +{ + public bool IsEnabled { get; set; } + public NodeScriptEntity? NodeScript { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/DataModelPathEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/DataModelPathEntity.cs similarity index 59% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/DataModelPathEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/DataModelPathEntity.cs index 0783e603f..4ebef8bc4 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/DataModelPathEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/DataModelPathEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class DataModelPathEntity +internal class DataModelPathEntity { public string Path { get; set; } = string.Empty; public string? DataModelId { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/FolderEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/FolderEntity.cs similarity index 63% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/FolderEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/FolderEntity.cs index ef181ff5d..ae467caa7 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/FolderEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/FolderEntity.cs @@ -1,9 +1,9 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Abstract; +using Artemis.Storage.Legacy.Entities.Profile.Abstract; using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class FolderEntity : RenderElementEntity +internal class FolderEntity : RenderElementEntity { public int Order { get; set; } public string? Name { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/KeyframeEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/KeyframeEntity.cs similarity index 66% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/KeyframeEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/KeyframeEntity.cs index fae285769..6f75fe047 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/KeyframeEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/KeyframeEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class KeyframeEntity +internal class KeyframeEntity { public TimeSpan Position { get; set; } public int Timeline { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LayerBrushEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/LayerBrushEntity.cs similarity index 66% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LayerBrushEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/LayerBrushEntity.cs index f0579e9ac..254c19e71 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LayerBrushEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/LayerBrushEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class LayerBrushEntity +internal class LayerBrushEntity { public string ProviderId { get; set; } = string.Empty; public string BrushType { get; set; } = string.Empty; diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LayerEffectEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/LayerEffectEntity.cs similarity index 77% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LayerEffectEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/LayerEffectEntity.cs index b3b8e5bdb..7f4c7e696 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LayerEffectEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/LayerEffectEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class LayerEffectEntity +internal class LayerEffectEntity { public string ProviderId { get; set; } = string.Empty; public string EffectType { get; set; } = string.Empty; diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LayerEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/LayerEntity.cs similarity index 73% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LayerEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/LayerEntity.cs index 57d5ea555..d00a62c20 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LayerEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/LayerEntity.cs @@ -1,10 +1,10 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Abstract; -using Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints; +using Artemis.Storage.Legacy.Entities.Profile.Abstract; +using Artemis.Storage.Legacy.Entities.Profile.AdaptionHints; using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class LayerEntity : RenderElementEntity +internal class LayerEntity : RenderElementEntity { public LayerEntity() { diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LedEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/LedEntity.cs similarity index 92% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LedEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/LedEntity.cs index b456a138c..5f7328bd6 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/LedEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/LedEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class LedEntity +internal class LedEntity { public string LedName { get; set; } = string.Empty; public string DeviceIdentifier { get; set; } = string.Empty; diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodeConnectionEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodeConnectionEntity.cs similarity index 90% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodeConnectionEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodeConnectionEntity.cs index d256cce6b..c186db470 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodeConnectionEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodeConnectionEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; +namespace Artemis.Storage.Legacy.Entities.Profile.Nodes; -public class NodeConnectionEntity +internal class NodeConnectionEntity { public NodeConnectionEntity() { diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodeEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodeEntity.cs similarity index 92% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodeEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodeEntity.cs index b25e9b0f7..314964430 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodeEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodeEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; +namespace Artemis.Storage.Legacy.Entities.Profile.Nodes; -public class NodeEntity +internal class NodeEntity { public NodeEntity() { diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodePinCollectionEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodePinCollectionEntity.cs similarity index 79% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodePinCollectionEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodePinCollectionEntity.cs index cdec98e6a..b10944b48 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodePinCollectionEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodePinCollectionEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; +namespace Artemis.Storage.Legacy.Entities.Profile.Nodes; -public class NodePinCollectionEntity +internal class NodePinCollectionEntity { public NodePinCollectionEntity() { diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodeScriptEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodeScriptEntity.cs similarity index 78% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodeScriptEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodeScriptEntity.cs index 5afeb39df..8da434571 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Nodes/NodeScriptEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/Nodes/NodeScriptEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; +namespace Artemis.Storage.Legacy.Entities.Profile.Nodes; -public class NodeScriptEntity +internal class NodeScriptEntity { public NodeScriptEntity() { diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileCategoryEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/ProfileCategoryEntity.cs similarity index 96% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileCategoryEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/ProfileCategoryEntity.cs index 0323db70d..c5b61012b 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileCategoryEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/ProfileCategoryEntity.cs @@ -3,9 +3,9 @@ using Artemis.Storage.Entities.Profile; using LiteDB; using Serilog; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class ProfileCategoryEntity +internal class ProfileCategoryEntity { public Guid Id { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileConfigurationEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/ProfileConfigurationEntity.cs similarity index 83% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileConfigurationEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/ProfileConfigurationEntity.cs index 89f68fe1d..482672a60 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileConfigurationEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/ProfileConfigurationEntity.cs @@ -1,8 +1,8 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; +using Artemis.Storage.Legacy.Entities.Profile.Nodes; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class ProfileConfigurationEntity +internal class ProfileConfigurationEntity { public string Name { get; set; } = string.Empty; public string? MaterialIcon { get; set; } diff --git a/src/Artemis.Storage.Legacy/Entities/Profile/ProfileConfigurationHotkeyEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/ProfileConfigurationHotkeyEntity.cs new file mode 100644 index 000000000..30cfb4a06 --- /dev/null +++ b/src/Artemis.Storage.Legacy/Entities/Profile/ProfileConfigurationHotkeyEntity.cs @@ -0,0 +1,7 @@ +namespace Artemis.Storage.Legacy.Entities.Profile; + +internal class ProfileConfigurationHotkeyEntity +{ + public int? Key { get; set; } + public int? Modifiers { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/ProfileEntity.cs similarity index 84% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/ProfileEntity.cs index cbfde4b61..dbbbfee9d 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/ProfileEntity.cs @@ -1,8 +1,8 @@ -using Artemis.Storage.Migrator.Legacy.Entities.General; +using Artemis.Storage.Legacy.Entities.General; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class ProfileEntity +internal class ProfileEntity { public ProfileEntity() { diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/PropertyEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/PropertyEntity.cs similarity index 64% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/PropertyEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/PropertyEntity.cs index 1a0a5d4b6..44a4406ab 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/PropertyEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/PropertyEntity.cs @@ -1,8 +1,8 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile.DataBindings; +using Artemis.Storage.Legacy.Entities.Profile.DataBindings; -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class PropertyEntity +internal class PropertyEntity { public string Identifier { get; set; } = string.Empty; public string Value { get; set; } = string.Empty; diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/PropertyGroupEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/PropertyGroupEntity.cs similarity index 68% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/PropertyGroupEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/PropertyGroupEntity.cs index 8097d36ba..2c7f316bb 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/PropertyGroupEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/PropertyGroupEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class PropertyGroupEntity +internal class PropertyGroupEntity { public string Identifier { get; set; } = string.Empty; public List Properties { get; set; } = new(); diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/TimelineEntity.cs b/src/Artemis.Storage.Legacy/Entities/Profile/TimelineEntity.cs similarity index 63% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Profile/TimelineEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Profile/TimelineEntity.cs index a9401abac..9a1f400e4 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/TimelineEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Profile/TimelineEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; +namespace Artemis.Storage.Legacy.Entities.Profile; -public class TimelineEntity +internal class TimelineEntity { public TimeSpan StartSegmentLength { get; set; } public TimeSpan MainSegmentLength { get; set; } diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Surface/DeviceEntity.cs b/src/Artemis.Storage.Legacy/Entities/Surface/DeviceEntity.cs similarity index 93% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Surface/DeviceEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Surface/DeviceEntity.cs index 52d86fbcc..fc3988dba 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Surface/DeviceEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Surface/DeviceEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Surface; +namespace Artemis.Storage.Legacy.Entities.Surface; -public class DeviceEntity +internal class DeviceEntity { public DeviceEntity() { @@ -65,13 +65,13 @@ public class DeviceEntity } } -public class InputMappingEntity +internal class InputMappingEntity { public int OriginalLedId { get; set; } public int MappedLedId { get; set; } } -public class DeviceInputIdentifierEntity +internal class DeviceInputIdentifierEntity { public string InputProvider { get; set; } = string.Empty; public object Identifier { get; set; } = string.Empty; diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Workshop/EntryEntity.cs b/src/Artemis.Storage.Legacy/Entities/Workshop/EntryEntity.cs similarity index 91% rename from src/Artemis.Storage.Migrator/Legacy/Entities/Workshop/EntryEntity.cs rename to src/Artemis.Storage.Legacy/Entities/Workshop/EntryEntity.cs index c5fea30d2..ec0d6c091 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Workshop/EntryEntity.cs +++ b/src/Artemis.Storage.Legacy/Entities/Workshop/EntryEntity.cs @@ -1,6 +1,6 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Workshop; +namespace Artemis.Storage.Legacy.Entities.Workshop; -public class EntryEntity +internal class EntryEntity { public Guid Id { get; set; } diff --git a/src/Artemis.Storage.Legacy/LegacyMigrationService.cs b/src/Artemis.Storage.Legacy/LegacyMigrationService.cs new file mode 100644 index 000000000..1c3b35d4f --- /dev/null +++ b/src/Artemis.Storage.Legacy/LegacyMigrationService.cs @@ -0,0 +1,163 @@ +using Artemis.Core; +using Artemis.Storage.Legacy.Entities.General; +using Artemis.Storage.Legacy.Entities.Plugins; +using Artemis.Storage.Legacy.Entities.Profile; +using Artemis.Storage.Legacy.Entities.Surface; +using Artemis.Storage.Legacy.Entities.Workshop; +using Artemis.Storage.Legacy.Migrations; +using Artemis.Storage.Legacy.Migrations.Storage; +using DryIoc; +using LiteDB; +using Serilog; + +namespace Artemis.Storage.Legacy; + +public static class LegacyMigrationService +{ + public static void MigrateToSqlite(IContainer container) + { + ILogger logger = container.Resolve(); + + // Before creating a DB context which is kinda expensive, check if there's anything to migrate + if (!File.Exists(Path.Combine(Constants.DataFolder, "database.db"))) + { + logger.Information("No legacy database found, nothing to migrate"); + return; + } + + using ArtemisDbContext dbContext = container.Resolve(); + MigrateToSqlite(logger, dbContext); + } + + public static void MigrateToSqlite(ILogger logger, ArtemisDbContext dbContext) + { + if (!File.Exists(Path.Combine(Constants.DataFolder, "database.db"))) + { + logger.Information("No legacy database found, nothing to migrate"); + return; + } + + logger.Information("Migrating legacy database..."); + + try + { + // Copy the database before using it, we're going to make some modifications to it and we don't want to mess up the original + string databasePath = Path.Combine(Constants.DataFolder, "database.db"); + string tempPath = Path.Combine(Constants.DataFolder, "temp.db"); + File.Copy(databasePath, tempPath, true); + + using LiteRepository repository = new($"FileName={tempPath}"); + + // Apply pending LiteDB migrations, this includes a migration that transforms namespaces to Artemis.Storage.Legacy + ApplyPendingMigrations(logger, repository); + + // Devices + if (!dbContext.Devices.Any()) + { + logger.Information("Migrating devices"); + List legacyDevices = repository.Query().Include(s => s.InputIdentifiers).ToList(); + dbContext.Devices.AddRange(legacyDevices.Select(l => l.Migrate())); + dbContext.SaveChanges(); + } + + // Entries + if (!dbContext.Entries.Any()) + { + logger.Information("Migrating entries"); + List legacyEntries = repository.Query().ToList(); + dbContext.Entries.AddRange(legacyEntries.Select(l => l.Migrate())); + dbContext.SaveChanges(); + } + + // Plugins + if (!dbContext.Plugins.Any()) + { + logger.Information("Migrating plugins"); + List legacyPlugins = repository.Query().ToList(); + dbContext.Plugins.AddRange(legacyPlugins.Select(l => l.Migrate())); + dbContext.SaveChanges(); + } + + // PluginSettings + if (!dbContext.PluginSettings.Any()) + { + logger.Information("Migrating plugin settings"); + List legacyPluginSettings = repository.Query().ToList(); + dbContext.PluginSettings.AddRange(legacyPluginSettings.Select(l => l.Migrate())); + dbContext.SaveChanges(); + } + + // ProfileCategories + if (!dbContext.ProfileCategories.Any()) + { + logger.Information("Migrating profile categories"); + List legacyProfileCategories = repository.Query().ToList(); + ILiteStorage profileIcons = repository.Database.GetStorage("profileIcons"); + List legacyProfiles = repository.Query().ToList(); + dbContext.ProfileCategories.AddRange(legacyProfileCategories.Select(l => l.Migrate(logger, legacyProfiles, profileIcons))); + dbContext.SaveChanges(); + } + + // Releases + if (!dbContext.Releases.Any()) + { + logger.Information("Migrating releases"); + List legacyReleases = repository.Query().ToList(); + dbContext.Releases.AddRange(legacyReleases.Select(l => l.Migrate())); + dbContext.SaveChanges(); + } + + // After a successful migration, keep the legacy database around for a while + File.Move(Path.Combine(Constants.DataFolder, "database.db"), Path.Combine(Constants.DataFolder, "legacy.db")); + + logger.Information("Legacy database migrated"); + } + catch (Exception e) + { + logger.Error(e, "Failed to migrate legacy database"); + throw; + } + finally + { + File.Delete(Path.Combine(Constants.DataFolder, "temp.db")); + } + } + + private static void ApplyPendingMigrations(ILogger logger, LiteRepository repository) + { + List migrations = + [ + new M0020AvaloniaReset(), + new M0021GradientNodes(), + new M0022TransitionNodes(), + new M0023LayoutProviders(), + new M0024NodeProviders(), + new M0025NodeProvidersProfileConfig(), + new M0026NodeStorage(logger), + new M0027Namespace() + ]; + + foreach (IStorageMigration storageMigration in migrations.OrderBy(m => m.UserVersion)) + { + if (repository.Database.UserVersion >= storageMigration.UserVersion) + continue; + + logger.Information("Applying storage migration {storageMigration} to update DB from v{oldVersion} to v{newVersion}", + storageMigration.GetType().Name, repository.Database.UserVersion, storageMigration.UserVersion); + + repository.Database.BeginTrans(); + try + { + storageMigration.Apply(repository); + } + catch (Exception) + { + repository.Database.Rollback(); + throw; + } + + repository.Database.Commit(); + repository.Database.UserVersion = storageMigration.UserVersion; + } + } +} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/IProfileMigration.cs b/src/Artemis.Storage.Legacy/Migrations/IProfileMigration.cs similarity index 75% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/IProfileMigration.cs rename to src/Artemis.Storage.Legacy/Migrations/IProfileMigration.cs index f5e9d8092..53d1d1eda 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/IProfileMigration.cs +++ b/src/Artemis.Storage.Legacy/Migrations/IProfileMigration.cs @@ -1,6 +1,6 @@ using System.Text.Json.Nodes; -namespace Artemis.Storage.Migrator.Legacy.Migrations; +namespace Artemis.Storage.Legacy.Migrations; public interface IProfileMigration { diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/IStorageMigration.cs b/src/Artemis.Storage.Legacy/Migrations/IStorageMigration.cs similarity index 70% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/IStorageMigration.cs rename to src/Artemis.Storage.Legacy/Migrations/IStorageMigration.cs index 4aee9aabd..18ba559ca 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/IStorageMigration.cs +++ b/src/Artemis.Storage.Legacy/Migrations/IStorageMigration.cs @@ -1,6 +1,6 @@ using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Migrations; +namespace Artemis.Storage.Legacy.Migrations; public interface IStorageMigration { diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0020AvaloniaReset.cs b/src/Artemis.Storage.Legacy/Migrations/Storage/M0020AvaloniaReset.cs similarity index 76% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0020AvaloniaReset.cs rename to src/Artemis.Storage.Legacy/Migrations/Storage/M0020AvaloniaReset.cs index de3478e7b..685585ffb 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0020AvaloniaReset.cs +++ b/src/Artemis.Storage.Legacy/Migrations/Storage/M0020AvaloniaReset.cs @@ -1,8 +1,8 @@ using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage; +namespace Artemis.Storage.Legacy.Migrations.Storage; -public class M0020AvaloniaReset : IStorageMigration +internal class M0020AvaloniaReset : IStorageMigration { public int UserVersion => 20; diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0021GradientNodes.cs b/src/Artemis.Storage.Legacy/Migrations/Storage/M0021GradientNodes.cs similarity index 92% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0021GradientNodes.cs rename to src/Artemis.Storage.Legacy/Migrations/Storage/M0021GradientNodes.cs index 354525008..02998e98c 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0021GradientNodes.cs +++ b/src/Artemis.Storage.Legacy/Migrations/Storage/M0021GradientNodes.cs @@ -1,10 +1,10 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile; -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; +using Artemis.Storage.Legacy.Entities.Profile; +using Artemis.Storage.Legacy.Entities.Profile.Nodes; using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage; +namespace Artemis.Storage.Legacy.Migrations.Storage; -public class M0021GradientNodes : IStorageMigration +internal class M0021GradientNodes : IStorageMigration { private void MigrateDataBinding(PropertyEntity property) { @@ -59,7 +59,7 @@ public class M0021GradientNodes : IStorageMigration { if (propertyGroup == null) return; - + foreach (PropertyGroupEntity propertyGroupPropertyGroup in propertyGroup.PropertyGroups) MigrateDataBinding(propertyGroupPropertyGroup); diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0022TransitionNodes.cs b/src/Artemis.Storage.Legacy/Migrations/Storage/M0022TransitionNodes.cs similarity index 91% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0022TransitionNodes.cs rename to src/Artemis.Storage.Legacy/Migrations/Storage/M0022TransitionNodes.cs index 7556b7840..369ab130c 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0022TransitionNodes.cs +++ b/src/Artemis.Storage.Legacy/Migrations/Storage/M0022TransitionNodes.cs @@ -1,11 +1,11 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile; -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions; -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; +using Artemis.Storage.Legacy.Entities.Profile; +using Artemis.Storage.Legacy.Entities.Profile.Conditions; +using Artemis.Storage.Legacy.Entities.Profile.Nodes; using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage; +namespace Artemis.Storage.Legacy.Migrations.Storage; -public class M0022TransitionNodes : IStorageMigration +internal class M0022TransitionNodes : IStorageMigration { private void MigrateNodeScript(NodeScriptEntity? nodeScript) { diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0023LayoutProviders.cs b/src/Artemis.Storage.Legacy/Migrations/Storage/M0023LayoutProviders.cs similarity index 88% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0023LayoutProviders.cs rename to src/Artemis.Storage.Legacy/Migrations/Storage/M0023LayoutProviders.cs index 602ba6f2e..1a8d7500b 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0023LayoutProviders.cs +++ b/src/Artemis.Storage.Legacy/Migrations/Storage/M0023LayoutProviders.cs @@ -1,8 +1,8 @@ using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage; +namespace Artemis.Storage.Legacy.Migrations.Storage; -public class M0023LayoutProviders : IStorageMigration +internal class M0023LayoutProviders : IStorageMigration { public int UserVersion => 23; @@ -19,9 +19,13 @@ public class M0023LayoutProviders : IStorageMigration bsonDocument.Add("LayoutParameter", new BsonValue(customLayoutPath.AsString)); } else if (bsonDocument.TryGetValue("DisableDefaultLayout", out BsonValue disableDefaultLayout) && disableDefaultLayout.AsBoolean) + { bsonDocument.Add("LayoutType", new BsonValue("None")); + } else + { bsonDocument.Add("LayoutType", new BsonValue("Default")); + } bsonDocument.Remove("CustomLayoutPath"); bsonDocument.Remove("DisableDefaultLayout"); diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0024NodeProviders.cs b/src/Artemis.Storage.Legacy/Migrations/Storage/M0024NodeProviders.cs similarity index 93% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0024NodeProviders.cs rename to src/Artemis.Storage.Legacy/Migrations/Storage/M0024NodeProviders.cs index 37d61c5d5..4617ae6d1 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0024NodeProviders.cs +++ b/src/Artemis.Storage.Legacy/Migrations/Storage/M0024NodeProviders.cs @@ -1,8 +1,8 @@ using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage; +namespace Artemis.Storage.Legacy.Migrations.Storage; -public class M0024NodeProviders : IStorageMigration +internal class M0024NodeProviders : IStorageMigration { public int UserVersion => 24; @@ -20,6 +20,7 @@ public class M0024NodeProviders : IStorageMigration categoriesToUpdate.Add(profileCategoryBson); } } + categoryCollection.Update(categoriesToUpdate); ILiteCollection collection = repository.Database.GetCollection("ProfileEntity"); @@ -28,15 +29,12 @@ public class M0024NodeProviders : IStorageMigration { BsonArray? folders = profileBson["Folders"]?.AsArray; BsonArray? layers = profileBson["Layers"]?.AsArray; - + if (folders != null) - { foreach (BsonValue folder in folders) MigrateProfileElement(folder.AsDocument); - } - + if (layers != null) - { foreach (BsonValue layer in layers) { MigrateProfileElement(layer.AsDocument); @@ -44,8 +42,7 @@ public class M0024NodeProviders : IStorageMigration MigratePropertyGroup(layer.AsDocument["TransformPropertyGroup"].AsDocument); MigratePropertyGroup(layer.AsDocument["LayerBrush"]?["PropertyGroup"].AsDocument); } - } - + profilesToUpdate.Add(profileBson); } @@ -56,10 +53,8 @@ public class M0024NodeProviders : IStorageMigration { BsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray; if (layerEffects != null) - { foreach (BsonValue layerEffect in layerEffects) MigratePropertyGroup(layerEffect.AsDocument["PropertyGroup"].AsDocument); - } BsonValue? displayCondition = profileElement["DisplayCondition"]; if (displayCondition != null) @@ -75,16 +70,12 @@ public class M0024NodeProviders : IStorageMigration BsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray; if (properties != null) - { foreach (BsonValue property in properties) MigrateNodeScript(property.AsDocument["DataBinding"]?["NodeScript"]?.AsDocument); - } if (propertyGroups != null) - { foreach (BsonValue childPropertyGroup in propertyGroups) MigratePropertyGroup(childPropertyGroup.AsDocument); - } } private void MigrateNodeScript(BsonDocument? nodeScript) diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0025NodeProvidersProfileConfig.cs b/src/Artemis.Storage.Legacy/Migrations/Storage/M0025NodeProvidersProfileConfig.cs similarity index 91% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0025NodeProvidersProfileConfig.cs rename to src/Artemis.Storage.Legacy/Migrations/Storage/M0025NodeProvidersProfileConfig.cs index bbb121956..bff6ff6ff 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0025NodeProvidersProfileConfig.cs +++ b/src/Artemis.Storage.Legacy/Migrations/Storage/M0025NodeProvidersProfileConfig.cs @@ -1,8 +1,8 @@ using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage; +namespace Artemis.Storage.Legacy.Migrations.Storage; -public class M0025NodeProvidersProfileConfig : IStorageMigration +internal class M0025NodeProvidersProfileConfig : IStorageMigration { public int UserVersion => 25; @@ -20,13 +20,14 @@ public class M0025NodeProvidersProfileConfig : IStorageMigration profile["Version"] = 2; MigrateNodeScript(profile["ActivationCondition"]?.AsDocument); } + toUpdate.Add(profileCategoryBson); } } - + categoryCollection.Update(toUpdate); } - + private void MigrateNodeScript(BsonDocument? nodeScript) { if (nodeScript == null || nodeScript.Keys.Count == 0) diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0026NodeStorage.cs b/src/Artemis.Storage.Legacy/Migrations/Storage/M0026NodeStorage.cs similarity index 97% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0026NodeStorage.cs rename to src/Artemis.Storage.Legacy/Migrations/Storage/M0026NodeStorage.cs index 1212455bb..cbea0db8d 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0026NodeStorage.cs +++ b/src/Artemis.Storage.Legacy/Migrations/Storage/M0026NodeStorage.cs @@ -3,9 +3,9 @@ using System.Text.Json.Nodes; using LiteDB; using Serilog; -namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage; +namespace Artemis.Storage.Legacy.Migrations.Storage; -public class M0026NodeStorage : IStorageMigration +internal class M0026NodeStorage : IStorageMigration { private readonly ILogger _logger; @@ -45,13 +45,10 @@ public class M0026NodeStorage : IStorageMigration BsonArray? layers = profileBson["Layers"]?.AsArray; if (folders != null) - { foreach (BsonValue folder in folders) MigrateProfileElement(folder.AsDocument); - } if (layers != null) - { foreach (BsonValue layer in layers) { MigrateProfileElement(layer.AsDocument); @@ -59,7 +56,6 @@ public class M0026NodeStorage : IStorageMigration MigratePropertyGroup(layer.AsDocument["TransformPropertyGroup"].AsDocument); MigratePropertyGroup(layer.AsDocument["LayerBrush"]?["PropertyGroup"].AsDocument); } - } profilesToUpdate.Add(profileBson); } @@ -71,10 +67,8 @@ public class M0026NodeStorage : IStorageMigration { BsonArray? layerEffects = profileElement["LayerEffects"]?.AsArray; if (layerEffects != null) - { foreach (BsonValue layerEffect in layerEffects) MigratePropertyGroup(layerEffect.AsDocument["PropertyGroup"].AsDocument); - } BsonValue? displayCondition = profileElement["DisplayCondition"]; if (displayCondition != null) @@ -90,16 +84,12 @@ public class M0026NodeStorage : IStorageMigration BsonArray? propertyGroups = propertyGroup["PropertyGroups"]?.AsArray; if (properties != null) - { foreach (BsonValue property in properties) MigrateNodeScript(property.AsDocument["DataBinding"]?["NodeScript"]?.AsDocument); - } if (propertyGroups != null) - { foreach (BsonValue childPropertyGroup in propertyGroups) MigratePropertyGroup(childPropertyGroup.AsDocument); - } } private void MigrateNodeScript(BsonDocument? nodeScript) @@ -112,10 +102,8 @@ public class M0026NodeStorage : IStorageMigration return; foreach (BsonValue node in nodes) - { // Migrate the storage of the node node["Storage"] = MigrateNodeStorageJson(node.AsDocument["Storage"]?.AsString, _logger); - } } private static string? MigrateNodeStorageJson(string? json, ILogger logger) diff --git a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0027Namespace.cs b/src/Artemis.Storage.Legacy/Migrations/Storage/M0027Namespace.cs similarity index 79% rename from src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0027Namespace.cs rename to src/Artemis.Storage.Legacy/Migrations/Storage/M0027Namespace.cs index 6a98a25eb..b0bee99a1 100644 --- a/src/Artemis.Storage.Migrator/Legacy/Migrations/Storage/M0027Namespace.cs +++ b/src/Artemis.Storage.Legacy/Migrations/Storage/M0027Namespace.cs @@ -1,8 +1,8 @@ using LiteDB; -namespace Artemis.Storage.Migrator.Legacy.Migrations.Storage; +namespace Artemis.Storage.Legacy.Migrations.Storage; -public class M0027Namespace : IStorageMigration +internal class M0027Namespace : IStorageMigration { public int UserVersion => 27; @@ -25,21 +25,17 @@ public class M0027Namespace : IStorageMigration foreach ((string? key, BsonValue? value) in document) { if (key == "_type") - { document[key] = document[key].AsString - .Replace("Artemis.Storage.Entities.Profile", "Artemis.Storage.Migrator.Legacy.Entities.Profile") - .Replace(", Artemis.Storage", ", Artemis.Storage.Migrator"); - } + .Replace("Artemis.Storage.Entities", "Artemis.Storage.Legacy.Entities") + .Replace(", Artemis.Storage", ", Artemis.Storage.Legacy"); else if (value.IsDocument) MigrateDocument(value.AsDocument); else if (value.IsArray) - { foreach (BsonValue bsonValue in value.AsArray) { if (bsonValue.IsDocument) MigrateDocument(bsonValue.AsDocument); } - } } } } \ No newline at end of file diff --git a/src/Artemis.Storage.Legacy/Program.cs b/src/Artemis.Storage.Legacy/Program.cs new file mode 100644 index 000000000..c225e03f5 --- /dev/null +++ b/src/Artemis.Storage.Legacy/Program.cs @@ -0,0 +1,22 @@ +// using Artemis.Core.DryIoc; +// using Artemis.Storage; +// using Artemis.Storage.Legacy; +// using DryIoc; +// using Microsoft.EntityFrameworkCore; +// using Serilog; +// +// using Container container = new(rules => rules +// .WithMicrosoftDependencyInjectionRules() +// .WithConcreteTypeDynamicRegistrations() +// .WithoutThrowOnRegisteringDisposableTransient()); +// +// container.RegisterCore(); +// +// ILogger logger = container.Resolve(); +// ArtemisDbContext dbContext = container.Resolve(); +// +// logger.Information("Applying pending migrations..."); +// dbContext.Database.Migrate(); +// logger.Information("Pending migrations applied"); +// +// MigrationService.MigrateToSqlite(logger, dbContext); \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/KeyboardSectionAdaptionHintEntity.cs b/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/KeyboardSectionAdaptionHintEntity.cs deleted file mode 100644 index 075f3ad9a..000000000 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/AdaptionHints/KeyboardSectionAdaptionHintEntity.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.AdaptionHints; - -public class KeyboardSectionAdaptionHintEntity : IAdaptionHintEntity -{ - public int Section { get; set; } -} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/AlwaysOnConditionEntity.cs b/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/AlwaysOnConditionEntity.cs deleted file mode 100644 index e644c4331..000000000 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/AlwaysOnConditionEntity.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions; - -public class AlwaysOnConditionEntity : IConditionEntity; \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/PlayOnceConditionEntity.cs b/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/PlayOnceConditionEntity.cs deleted file mode 100644 index 82fb095b1..000000000 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/PlayOnceConditionEntity.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions; - -public class PlayOnceConditionEntity : IConditionEntity; \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/StaticConditionEntity.cs b/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/StaticConditionEntity.cs deleted file mode 100644 index 065bd92bd..000000000 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/Conditions/StaticConditionEntity.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; - -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.Conditions; - -public class StaticConditionEntity : IConditionEntity -{ - public int PlayMode { get; set; } - public int StopMode { get; set; } - public NodeScriptEntity? Script { get; set; } -} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/DataBindings/DataBindingEntity.cs b/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/DataBindings/DataBindingEntity.cs deleted file mode 100644 index 74aa3851e..000000000 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/DataBindings/DataBindingEntity.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Artemis.Storage.Migrator.Legacy.Entities.Profile.Nodes; - -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile.DataBindings; - -public class DataBindingEntity -{ - public bool IsEnabled { get; set; } - public NodeScriptEntity? NodeScript { get; set; } -} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileConfigurationHotkeyEntity.cs b/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileConfigurationHotkeyEntity.cs deleted file mode 100644 index a0572cc91..000000000 --- a/src/Artemis.Storage.Migrator/Legacy/Entities/Profile/ProfileConfigurationHotkeyEntity.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Artemis.Storage.Migrator.Legacy.Entities.Profile; - -public class ProfileConfigurationHotkeyEntity -{ - public int? Key { get; set; } - public int? Modifiers { get; set; } -} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Legacy/StorageMigrationService.cs b/src/Artemis.Storage.Migrator/Legacy/StorageMigrationService.cs deleted file mode 100644 index 86f4f1384..000000000 --- a/src/Artemis.Storage.Migrator/Legacy/StorageMigrationService.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Artemis.Storage.Migrator.Legacy.Migrations; -using LiteDB; -using Serilog; - -namespace Artemis.Storage.Migrator.Legacy; - -public static class StorageMigrationService -{ - public static void ApplyPendingMigrations(ILogger logger, LiteRepository repository, IList migrations) - { - foreach (IStorageMigration storageMigration in migrations.OrderBy(m => m.UserVersion)) - { - if (repository.Database.UserVersion >= storageMigration.UserVersion) - continue; - - logger.Information("Applying storage migration {storageMigration} to update DB from v{oldVersion} to v{newVersion}", - storageMigration.GetType().Name, repository.Database.UserVersion, storageMigration.UserVersion); - - repository.Database.BeginTrans(); - try - { - storageMigration.Apply(repository); - } - catch (Exception) - { - repository.Database.Rollback(); - throw; - } - - repository.Database.Commit(); - repository.Database.UserVersion = storageMigration.UserVersion; - } - } -} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/Program.cs b/src/Artemis.Storage.Migrator/Program.cs deleted file mode 100644 index ba15b7bfa..000000000 --- a/src/Artemis.Storage.Migrator/Program.cs +++ /dev/null @@ -1,142 +0,0 @@ -using Artemis.Core; -using Artemis.Core.DryIoc; -using Artemis.Storage.Migrator.Legacy; -using Artemis.Storage.Migrator.Legacy.Entities.General; -using Artemis.Storage.Migrator.Legacy.Entities.Plugins; -using Artemis.Storage.Migrator.Legacy.Entities.Profile; -using Artemis.Storage.Migrator.Legacy.Entities.Surface; -using Artemis.Storage.Migrator.Legacy.Entities.Workshop; -using Artemis.Storage.Migrator.Legacy.Migrations.Storage; -using DryIoc; -using LiteDB; -using Microsoft.EntityFrameworkCore; -using Serilog; - -namespace Artemis.Storage.Migrator; - -class Program -{ - static void Main(string[] args) - { - using Container container = new(rules => rules - .WithMicrosoftDependencyInjectionRules() - .WithConcreteTypeDynamicRegistrations() - .WithoutThrowOnRegisteringDisposableTransient()); - - container.RegisterCore(); - - ILogger logger = container.Resolve(); - ArtemisDbContext dbContext = container.Resolve(); - logger.Information("Applying pending migrations..."); - dbContext.Database.Migrate(); - logger.Information("Pending migrations applied"); - - if (!File.Exists(Path.Combine(Constants.DataFolder, "database.db"))) - { - logger.Information("No legacy database found, nothing to migrate"); - return; - } - - logger.Information("Migrating legacy database..."); - - try - { - MigrateLegacyDatabase(logger, dbContext); - // After a successful migration, keep the legacy database around for a while - File.Move(Path.Combine(Constants.DataFolder, "database.db"), Path.Combine(Constants.DataFolder, "legacy.db")); - } - catch (Exception e) - { - logger.Error(e, "Failed to migrate legacy database"); - throw; - } - finally - { - File.Delete(Path.Combine(Constants.DataFolder, "temp.db")); - } - - logger.Information("Legacy database migrated"); - } - - private static void MigrateLegacyDatabase(ILogger logger, ArtemisDbContext dbContext) - { - // Copy the database before using it, we're going to make some modifications to it and we don't want to mess up the original - string databasePath = Path.Combine(Constants.DataFolder, "database.db"); - string tempPath = Path.Combine(Constants.DataFolder, "temp.db"); - File.Copy(databasePath, tempPath, true); - - using LiteRepository repository = new($"FileName={tempPath}"); - - // Apply pending LiteDB migrations, this includes a migration that transforms namespaces to Artemis.Storage.Migrator - StorageMigrationService.ApplyPendingMigrations( - logger, - repository, - [ - new M0020AvaloniaReset(), - new M0021GradientNodes(), - new M0022TransitionNodes(), - new M0023LayoutProviders(), - new M0024NodeProviders(), - new M0025NodeProvidersProfileConfig(), - new M0026NodeStorage(logger), - new M0027Namespace(), - ] - ); - - // Devices - if (!dbContext.Devices.Any()) - { - logger.Information("Migrating devices"); - List legacyDevices = repository.Query().Include(s => s.InputIdentifiers).ToList(); - dbContext.Devices.AddRange(legacyDevices.Select(l => l.Migrate())); - dbContext.SaveChanges(); - } - - // Entries - if (!dbContext.Entries.Any()) - { - logger.Information("Migrating entries"); - List legacyEntries = repository.Query().ToList(); - dbContext.Entries.AddRange(legacyEntries.Select(l => l.Migrate())); - dbContext.SaveChanges(); - } - - // Plugins - if (!dbContext.Plugins.Any()) - { - logger.Information("Migrating plugins"); - List legacyPlugins = repository.Query().ToList(); - dbContext.Plugins.AddRange(legacyPlugins.Select(l => l.Migrate())); - dbContext.SaveChanges(); - } - - // PluginSettings - if (!dbContext.PluginSettings.Any()) - { - logger.Information("Migrating plugin settings"); - List legacyPluginSettings = repository.Query().ToList(); - dbContext.PluginSettings.AddRange(legacyPluginSettings.Select(l => l.Migrate())); - dbContext.SaveChanges(); - } - - // ProfileCategories - if (!dbContext.ProfileCategories.Any()) - { - logger.Information("Migrating profile categories"); - List legacyProfileCategories = repository.Query().ToList(); - ILiteStorage profileIcons = repository.Database.GetStorage("profileIcons"); - List legacyProfiles = repository.Query().ToList(); - dbContext.ProfileCategories.AddRange(legacyProfileCategories.Select(l => l.Migrate(logger, legacyProfiles, profileIcons))); - dbContext.SaveChanges(); - } - - // Releases - if (!dbContext.Releases.Any()) - { - logger.Information("Migrating releases"); - List legacyReleases = repository.Query().ToList(); - dbContext.Releases.AddRange(legacyReleases.Select(l => l.Migrate())); - dbContext.SaveChanges(); - } - } -} \ No newline at end of file diff --git a/src/Artemis.Storage.Migrator/artemis.db b/src/Artemis.Storage.Migrator/artemis.db deleted file mode 100644 index 286e00251800998db3fc3ad17b0ae79573adf4ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86016 zcmeI&&u`mg7{Kwk?UMdj+x_Td(6q@!LRzG;{zB>s7t+)%*3zUT-Dp85GL73=WJ!sg zK@S|#F%J9%+&S}iaOcJW2`(J?3pnyRvE4d(W0d2pZ`3G>{l3ooe4fXz-x{;cgNPVPfsZ?r0Jnx8S@R$>Crh*URRk`wh)Z2;FqmzH;7ynHyrG8B< z{I>YZ_34G5XKQo6&-^sIGTol}JhL#poPLo0W6Het*TloACFOh3aQsL2gQbjmys308 zyIHrsH4bb0?beCiunMiFYuZh#tv6lUJr6gVu65dKpBr^~yE}!7oF?6Q9oT*x_jZ^8=X_Txnr4br)>oz?``XU5W^mBu{1p9 z;YPK7$KWvjXouVNh8p?CZ0?nHGox;9DnD4R`DMeB$0*-=%OBf8eyga*@XXI@;*mA# zS?xeSJkUyI@qAh=YK3yCdQiz5r32CXNtniHcC*@k#n{VNjqT9ZdLdse~322j^#&Ja1XU(VJe$i?0$DsPF2P;aZBGEPi!}()BB2F!#fQ@=r~X?tw!Mb-l)#YQiU6{}&Hj^zZe3(^^Y^f_lV9oKA#?Bv}bf5KhFzPylD3-?CF9(-eMHF&ppaepqOE-x#uzKYCn z;b{}pc(~zuH147OV*p6{N+e3=i_t||Xf+z}dBl?kD0xvt$jb^4_je3~85?GlL!Pz93*kjAuel?+zj^bM?6HyKT#A#x>XylSSPA znDZ~l`u_8C#}*+J&GS}AT=Pa1S+R9`wOL>G@+V2Q-~a0Go}r!lW?NiwT<>x))V&Z+ z>cP%|>NJ{X9oMK^;@0cL7MJk2W_#w@nRf*kXyaA#R9q$drBz$?-(2e+Dj9WSL%AsT zrkq+$-`TTI`#;*9k8Q^lw|&x$6VWP{wz;hN@R;6N9;w;EdzBFflAH?SB&c_eUHPOS zB#eo)`o+em$yfS4wN>fnNpXuk?cHY2i>I>qXG;9>KmY**5I_I{1Q0*~0R#|00D(7D z;Jz}ssjjW8y}z=)@_21!eRFNKW;AWrHXDy0tvp(r6>%wxf2YJB4+IcE009ILKmY** z5I_I{1Q2+m1>TMaCAbPO?91|e|2q1s}0tg_000IagfB*ul z|5F19Ab Devices => Set(); public DbSet Entries => Set(); public DbSet Plugins => Set(); + public DbSet PluginFeatures => Set(); public DbSet PluginSettings => Set(); public DbSet ProfileCategories => Set(); + public DbSet ProfileContainers => Set(); public DbSet Releases => Set(); public string DataFolder { get; set; } = string.Empty; diff --git a/src/Artemis.Storage/Entities/General/ReleaseEntity.cs b/src/Artemis.Storage/Entities/General/ReleaseEntity.cs index f83efb6f1..47619b3c7 100644 --- a/src/Artemis.Storage/Entities/General/ReleaseEntity.cs +++ b/src/Artemis.Storage/Entities/General/ReleaseEntity.cs @@ -1,11 +1,17 @@ using System; +using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; namespace Artemis.Storage.Entities.General; +[Index(nameof(Version), IsUnique = true)] +[Index(nameof(InstalledAt))] public class ReleaseEntity { public Guid Id { get; set; } + [MaxLength(64)] public string Version { get; set; } = string.Empty; + public DateTimeOffset? InstalledAt { get; set; } } \ No newline at end of file diff --git a/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs b/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs index 0a0ca3b16..faf43f951 100644 --- a/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs +++ b/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; +using Microsoft.EntityFrameworkCore; namespace Artemis.Storage.Entities.Plugins; /// /// Represents the configuration of a plugin, each plugin has one configuration /// +[Index(nameof(PluginGuid), IsUnique = true)] public class PluginEntity { public PluginEntity() @@ -14,6 +17,7 @@ public class PluginEntity } public Guid Id { get; set; } + public Guid PluginGuid { get; set; } public bool IsEnabled { get; set; } public List Features { get; set; } @@ -25,7 +29,7 @@ public class PluginEntity public class PluginFeatureEntity { public Guid Id { get; set; } - + public string Type { get; set; } = string.Empty; public bool IsEnabled { get; set; } } \ No newline at end of file diff --git a/src/Artemis.Storage/Entities/Plugins/PluginSettingEntity.cs b/src/Artemis.Storage/Entities/Plugins/PluginSettingEntity.cs index 1d604c28a..b386b34d6 100644 --- a/src/Artemis.Storage/Entities/Plugins/PluginSettingEntity.cs +++ b/src/Artemis.Storage/Entities/Plugins/PluginSettingEntity.cs @@ -1,15 +1,20 @@ using System; +using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; namespace Artemis.Storage.Entities.Plugins; /// /// Represents the setting of a plugin, a plugin can have multiple settings /// +[Index(nameof(Name), nameof(PluginGuid), IsUnique = true)] +[Index(nameof(PluginGuid))] public class PluginSettingEntity { public Guid Id { get; set; } public Guid PluginGuid { get; set; } + [MaxLength(128)] public string Name { get; set; } = string.Empty; public string Value { get; set; } = string.Empty; } \ No newline at end of file diff --git a/src/Artemis.Storage/Entities/Profile/ProfileCategoryEntity.cs b/src/Artemis.Storage/Entities/Profile/ProfileCategoryEntity.cs index 02a797011..b7a3c15f4 100644 --- a/src/Artemis.Storage/Entities/Profile/ProfileCategoryEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/ProfileCategoryEntity.cs @@ -1,12 +1,16 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; namespace Artemis.Storage.Entities.Profile; +[Index(nameof(Name), IsUnique = true)] public class ProfileCategoryEntity { public Guid Id { get; set; } + [MaxLength(64)] public string Name { get; set; } = string.Empty; public bool IsCollapsed { get; set; } public bool IsSuspended { get; set; } diff --git a/src/Artemis.Storage/Entities/RawProfileContainer.cs b/src/Artemis.Storage/Entities/RawProfileContainer.cs new file mode 100644 index 000000000..4638f3e29 --- /dev/null +++ b/src/Artemis.Storage/Entities/RawProfileContainer.cs @@ -0,0 +1,10 @@ +using System; + +namespace Artemis.Storage.Entities; + +internal class RawProfileContainer +{ + public Guid Id { get; set; } + public string ProfileConfiguration { get; set; } + public string Profile { get; set; } +} \ No newline at end of file diff --git a/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs b/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs index 374a20941..6500b9b1d 100644 --- a/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs +++ b/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; namespace Artemis.Storage.Entities.Surface; @@ -11,8 +12,12 @@ public class DeviceEntity Categories = new List(); } + [MaxLength(512)] public string Id { get; set; } = string.Empty; + + [MaxLength(512)] public string DeviceProvider { get; set; } = string.Empty; + public float X { get; set; } public float Y { get; set; } public float Rotation { get; set; } @@ -22,10 +27,16 @@ public class DeviceEntity public float GreenScale { get; set; } public float BlueScale { get; set; } public bool IsEnabled { get; set; } - + public int PhysicalLayout { get; set; } + + [MaxLength(32)] public string? LogicalLayout { get; set; } + + [MaxLength(64)] public string? LayoutType { get; set; } + + [MaxLength(512)] public string? LayoutParameter { get; set; } public List InputIdentifiers { get; set; } diff --git a/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs b/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs index cd828721c..37cdd4cfa 100644 --- a/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs +++ b/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs @@ -1,22 +1,23 @@ using System; using System.Collections.Generic; -using System.Text.Json.Nodes; +using Microsoft.EntityFrameworkCore; namespace Artemis.Storage.Entities.Workshop; +[Index(nameof(EntryId), IsUnique = true)] public class EntryEntity { public Guid Id { get; set; } - + public long EntryId { get; set; } public int EntryType { get; set; } - - public string Author { get; set; } = string.Empty; + + public string Author { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public long ReleaseId { get; set; } public string ReleaseVersion { get; set; } = string.Empty; public DateTimeOffset InstalledAt { get; set; } - public Dictionary Metadata { get; set; } + public Dictionary? Metadata { get; set; } } \ No newline at end of file diff --git a/src/Artemis.Storage/Exceptions/ArtemisStorageException.cs b/src/Artemis.Storage/Exceptions/ArtemisStorageException.cs new file mode 100644 index 000000000..85e08a3df --- /dev/null +++ b/src/Artemis.Storage/Exceptions/ArtemisStorageException.cs @@ -0,0 +1,14 @@ +using System; + +namespace Artemis.Storage.Exceptions; + +public class ArtemisStorageException : Exception +{ + public ArtemisStorageException(string message) : base(message) + { + } + + public ArtemisStorageException(string message, Exception innerException) : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/Artemis.Storage/Migrations/20240308203921_Initial.Designer.cs b/src/Artemis.Storage/Migrations/20240310201706_Initial.Designer.cs similarity index 90% rename from src/Artemis.Storage/Migrations/20240308203921_Initial.Designer.cs rename to src/Artemis.Storage/Migrations/20240310201706_Initial.Designer.cs index 14b41beeb..bb62ee588 100644 --- a/src/Artemis.Storage/Migrations/20240308203921_Initial.Designer.cs +++ b/src/Artemis.Storage/Migrations/20240310201706_Initial.Designer.cs @@ -11,7 +11,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Artemis.Storage.Migrations { [DbContext(typeof(ArtemisDbContext))] - [Migration("20240308203921_Initial")] + [Migration("20240310201706_Initial")] partial class Initial { /// @@ -31,10 +31,16 @@ namespace Artemis.Storage.Migrations b.Property("Version") .IsRequired() + .HasMaxLength(64) .HasColumnType("TEXT"); b.HasKey("Id"); + b.HasIndex("InstalledAt"); + + b.HasIndex("Version") + .IsUnique(); + b.ToTable("Releases"); }); @@ -47,8 +53,14 @@ namespace Artemis.Storage.Migrations b.Property("IsEnabled") .HasColumnType("INTEGER"); + b.Property("PluginGuid") + .HasColumnType("TEXT"); + b.HasKey("Id"); + b.HasIndex("PluginGuid") + .IsUnique(); + b.ToTable("Plugins"); }); @@ -72,7 +84,7 @@ namespace Artemis.Storage.Migrations b.HasIndex("PluginEntityId"); - b.ToTable("PluginFeatureEntity"); + b.ToTable("PluginFeatures"); }); modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginSettingEntity", b => @@ -83,6 +95,7 @@ namespace Artemis.Storage.Migrations b.Property("Name") .IsRequired() + .HasMaxLength(128) .HasColumnType("TEXT"); b.Property("PluginGuid") @@ -94,6 +107,11 @@ namespace Artemis.Storage.Migrations b.HasKey("Id"); + b.HasIndex("PluginGuid"); + + b.HasIndex("Name", "PluginGuid") + .IsUnique(); + b.ToTable("PluginSettings"); }); @@ -111,6 +129,7 @@ namespace Artemis.Storage.Migrations b.Property("Name") .IsRequired() + .HasMaxLength(64) .HasColumnType("TEXT"); b.Property("Order") @@ -118,6 +137,9 @@ namespace Artemis.Storage.Migrations b.HasKey("Id"); + b.HasIndex("Name") + .IsUnique(); + b.ToTable("ProfileCategories"); }); @@ -146,12 +168,13 @@ namespace Artemis.Storage.Migrations b.HasIndex("ProfileCategoryId"); - b.ToTable("ProfileContainerEntity"); + b.ToTable("ProfileContainers"); }); modelBuilder.Entity("Artemis.Storage.Entities.Surface.DeviceEntity", b => { b.Property("Id") + .HasMaxLength(512) .HasColumnType("TEXT"); b.Property("BlueScale") @@ -163,6 +186,7 @@ namespace Artemis.Storage.Migrations b.Property("DeviceProvider") .IsRequired() + .HasMaxLength(512) .HasColumnType("TEXT"); b.Property("GreenScale") @@ -172,12 +196,15 @@ namespace Artemis.Storage.Migrations .HasColumnType("INTEGER"); b.Property("LayoutParameter") + .HasMaxLength(512) .HasColumnType("TEXT"); b.Property("LayoutType") + .HasMaxLength(64) .HasColumnType("TEXT"); b.Property("LogicalLayout") + .HasMaxLength(32) .HasColumnType("TEXT"); b.Property("PhysicalLayout") @@ -226,7 +253,6 @@ namespace Artemis.Storage.Migrations .HasColumnType("TEXT"); b.Property("Metadata") - .IsRequired() .HasColumnType("TEXT"); b.Property("Name") @@ -242,6 +268,9 @@ namespace Artemis.Storage.Migrations b.HasKey("Id"); + b.HasIndex("EntryId") + .IsUnique(); + b.ToTable("Entries"); }); diff --git a/src/Artemis.Storage/Migrations/20240308203921_Initial.cs b/src/Artemis.Storage/Migrations/20240310201706_Initial.cs similarity index 74% rename from src/Artemis.Storage/Migrations/20240308203921_Initial.cs rename to src/Artemis.Storage/Migrations/20240310201706_Initial.cs index 607c92cc6..286f29922 100644 --- a/src/Artemis.Storage/Migrations/20240308203921_Initial.cs +++ b/src/Artemis.Storage/Migrations/20240310201706_Initial.cs @@ -15,8 +15,8 @@ namespace Artemis.Storage.Migrations name: "Devices", columns: table => new { - Id = table.Column(type: "TEXT", nullable: false), - DeviceProvider = table.Column(type: "TEXT", nullable: false), + Id = table.Column(type: "TEXT", maxLength: 512, nullable: false), + DeviceProvider = table.Column(type: "TEXT", maxLength: 512, nullable: false), X = table.Column(type: "REAL", nullable: false), Y = table.Column(type: "REAL", nullable: false), Rotation = table.Column(type: "REAL", nullable: false), @@ -27,9 +27,9 @@ namespace Artemis.Storage.Migrations BlueScale = table.Column(type: "REAL", nullable: false), IsEnabled = table.Column(type: "INTEGER", nullable: false), PhysicalLayout = table.Column(type: "INTEGER", nullable: false), - LogicalLayout = table.Column(type: "TEXT", nullable: true), - LayoutType = table.Column(type: "TEXT", nullable: true), - LayoutParameter = table.Column(type: "TEXT", nullable: true), + LogicalLayout = table.Column(type: "TEXT", maxLength: 32, nullable: true), + LayoutType = table.Column(type: "TEXT", maxLength: 64, nullable: true), + LayoutParameter = table.Column(type: "TEXT", maxLength: 512, nullable: true), Categories = table.Column(type: "TEXT", nullable: false), InputIdentifiers = table.Column(type: "TEXT", nullable: false), InputMappings = table.Column(type: "TEXT", nullable: false) @@ -51,7 +51,7 @@ namespace Artemis.Storage.Migrations ReleaseId = table.Column(type: "INTEGER", nullable: false), ReleaseVersion = table.Column(type: "TEXT", nullable: false), InstalledAt = table.Column(type: "TEXT", nullable: false), - Metadata = table.Column(type: "TEXT", nullable: false) + Metadata = table.Column(type: "TEXT", nullable: true) }, constraints: table => { @@ -63,6 +63,7 @@ namespace Artemis.Storage.Migrations columns: table => new { Id = table.Column(type: "TEXT", nullable: false), + PluginGuid = table.Column(type: "TEXT", nullable: false), IsEnabled = table.Column(type: "INTEGER", nullable: false) }, constraints: table => @@ -76,7 +77,7 @@ namespace Artemis.Storage.Migrations { Id = table.Column(type: "TEXT", nullable: false), PluginGuid = table.Column(type: "TEXT", nullable: false), - Name = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 128, nullable: false), Value = table.Column(type: "TEXT", nullable: false) }, constraints: table => @@ -89,7 +90,7 @@ namespace Artemis.Storage.Migrations columns: table => new { Id = table.Column(type: "TEXT", nullable: false), - Name = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 64, nullable: false), IsCollapsed = table.Column(type: "INTEGER", nullable: false), IsSuspended = table.Column(type: "INTEGER", nullable: false), Order = table.Column(type: "INTEGER", nullable: false) @@ -104,7 +105,7 @@ namespace Artemis.Storage.Migrations columns: table => new { Id = table.Column(type: "TEXT", nullable: false), - Version = table.Column(type: "TEXT", nullable: false), + Version = table.Column(type: "TEXT", maxLength: 64, nullable: false), InstalledAt = table.Column(type: "TEXT", nullable: true) }, constraints: table => @@ -113,7 +114,7 @@ namespace Artemis.Storage.Migrations }); migrationBuilder.CreateTable( - name: "PluginFeatureEntity", + name: "PluginFeatures", columns: table => new { Id = table.Column(type: "TEXT", nullable: false), @@ -123,16 +124,16 @@ namespace Artemis.Storage.Migrations }, constraints: table => { - table.PrimaryKey("PK_PluginFeatureEntity", x => x.Id); + table.PrimaryKey("PK_PluginFeatures", x => x.Id); table.ForeignKey( - name: "FK_PluginFeatureEntity_Plugins_PluginEntityId", + name: "FK_PluginFeatures_Plugins_PluginEntityId", column: x => x.PluginEntityId, principalTable: "Plugins", principalColumn: "Id"); }); migrationBuilder.CreateTable( - name: "ProfileContainerEntity", + name: "ProfileContainers", columns: table => new { Id = table.Column(type: "TEXT", nullable: false), @@ -143,9 +144,9 @@ namespace Artemis.Storage.Migrations }, constraints: table => { - table.PrimaryKey("PK_ProfileContainerEntity", x => x.Id); + table.PrimaryKey("PK_ProfileContainers", x => x.Id); table.ForeignKey( - name: "FK_ProfileContainerEntity_ProfileCategories_ProfileCategoryId", + name: "FK_ProfileContainers_ProfileCategories_ProfileCategoryId", column: x => x.ProfileCategoryId, principalTable: "ProfileCategories", principalColumn: "Id", @@ -153,14 +154,54 @@ namespace Artemis.Storage.Migrations }); migrationBuilder.CreateIndex( - name: "IX_PluginFeatureEntity_PluginEntityId", - table: "PluginFeatureEntity", + name: "IX_Entries_EntryId", + table: "Entries", + column: "EntryId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_PluginFeatures_PluginEntityId", + table: "PluginFeatures", column: "PluginEntityId"); migrationBuilder.CreateIndex( - name: "IX_ProfileContainerEntity_ProfileCategoryId", - table: "ProfileContainerEntity", + name: "IX_Plugins_PluginGuid", + table: "Plugins", + column: "PluginGuid", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_PluginSettings_Name_PluginGuid", + table: "PluginSettings", + columns: new[] { "Name", "PluginGuid" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_PluginSettings_PluginGuid", + table: "PluginSettings", + column: "PluginGuid"); + + migrationBuilder.CreateIndex( + name: "IX_ProfileCategories_Name", + table: "ProfileCategories", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ProfileContainers_ProfileCategoryId", + table: "ProfileContainers", column: "ProfileCategoryId"); + + migrationBuilder.CreateIndex( + name: "IX_Releases_InstalledAt", + table: "Releases", + column: "InstalledAt"); + + migrationBuilder.CreateIndex( + name: "IX_Releases_Version", + table: "Releases", + column: "Version", + unique: true); } /// @@ -173,13 +214,13 @@ namespace Artemis.Storage.Migrations name: "Entries"); migrationBuilder.DropTable( - name: "PluginFeatureEntity"); + name: "PluginFeatures"); migrationBuilder.DropTable( name: "PluginSettings"); migrationBuilder.DropTable( - name: "ProfileContainerEntity"); + name: "ProfileContainers"); migrationBuilder.DropTable( name: "Releases"); diff --git a/src/Artemis.Storage/Migrations/ArtemisDbContextModelSnapshot.cs b/src/Artemis.Storage/Migrations/ArtemisDbContextModelSnapshot.cs index bd8df8c96..270d88797 100644 --- a/src/Artemis.Storage/Migrations/ArtemisDbContextModelSnapshot.cs +++ b/src/Artemis.Storage/Migrations/ArtemisDbContextModelSnapshot.cs @@ -28,10 +28,16 @@ namespace Artemis.Storage.Migrations b.Property("Version") .IsRequired() + .HasMaxLength(64) .HasColumnType("TEXT"); b.HasKey("Id"); + b.HasIndex("InstalledAt"); + + b.HasIndex("Version") + .IsUnique(); + b.ToTable("Releases"); }); @@ -44,8 +50,14 @@ namespace Artemis.Storage.Migrations b.Property("IsEnabled") .HasColumnType("INTEGER"); + b.Property("PluginGuid") + .HasColumnType("TEXT"); + b.HasKey("Id"); + b.HasIndex("PluginGuid") + .IsUnique(); + b.ToTable("Plugins"); }); @@ -69,7 +81,7 @@ namespace Artemis.Storage.Migrations b.HasIndex("PluginEntityId"); - b.ToTable("PluginFeatureEntity"); + b.ToTable("PluginFeatures"); }); modelBuilder.Entity("Artemis.Storage.Entities.Plugins.PluginSettingEntity", b => @@ -80,6 +92,7 @@ namespace Artemis.Storage.Migrations b.Property("Name") .IsRequired() + .HasMaxLength(128) .HasColumnType("TEXT"); b.Property("PluginGuid") @@ -91,6 +104,11 @@ namespace Artemis.Storage.Migrations b.HasKey("Id"); + b.HasIndex("PluginGuid"); + + b.HasIndex("Name", "PluginGuid") + .IsUnique(); + b.ToTable("PluginSettings"); }); @@ -108,6 +126,7 @@ namespace Artemis.Storage.Migrations b.Property("Name") .IsRequired() + .HasMaxLength(64) .HasColumnType("TEXT"); b.Property("Order") @@ -115,6 +134,9 @@ namespace Artemis.Storage.Migrations b.HasKey("Id"); + b.HasIndex("Name") + .IsUnique(); + b.ToTable("ProfileCategories"); }); @@ -143,12 +165,13 @@ namespace Artemis.Storage.Migrations b.HasIndex("ProfileCategoryId"); - b.ToTable("ProfileContainerEntity"); + b.ToTable("ProfileContainers"); }); modelBuilder.Entity("Artemis.Storage.Entities.Surface.DeviceEntity", b => { b.Property("Id") + .HasMaxLength(512) .HasColumnType("TEXT"); b.Property("BlueScale") @@ -160,6 +183,7 @@ namespace Artemis.Storage.Migrations b.Property("DeviceProvider") .IsRequired() + .HasMaxLength(512) .HasColumnType("TEXT"); b.Property("GreenScale") @@ -169,12 +193,15 @@ namespace Artemis.Storage.Migrations .HasColumnType("INTEGER"); b.Property("LayoutParameter") + .HasMaxLength(512) .HasColumnType("TEXT"); b.Property("LayoutType") + .HasMaxLength(64) .HasColumnType("TEXT"); b.Property("LogicalLayout") + .HasMaxLength(32) .HasColumnType("TEXT"); b.Property("PhysicalLayout") @@ -223,7 +250,6 @@ namespace Artemis.Storage.Migrations .HasColumnType("TEXT"); b.Property("Metadata") - .IsRequired() .HasColumnType("TEXT"); b.Property("Name") @@ -239,6 +265,9 @@ namespace Artemis.Storage.Migrations b.HasKey("Id"); + b.HasIndex("EntryId") + .IsUnique(); + b.ToTable("Entries"); }); diff --git a/src/Artemis.Storage/Repositories/DeviceRepository.cs b/src/Artemis.Storage/Repositories/DeviceRepository.cs index 28387fa6e..2eb7098c2 100644 --- a/src/Artemis.Storage/Repositories/DeviceRepository.cs +++ b/src/Artemis.Storage/Repositories/DeviceRepository.cs @@ -1,43 +1,50 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Artemis.Storage.Entities.Surface; using Artemis.Storage.Repositories.Interfaces; namespace Artemis.Storage.Repositories; -internal class DeviceRepository : IDeviceRepository +internal class DeviceRepository(Func getContext) : IDeviceRepository { - private readonly ArtemisDbContext _dbContext; - - public DeviceRepository(ArtemisDbContext dbContext) - { - _dbContext = dbContext; - } - public void Add(DeviceEntity deviceEntity) { - _dbContext.Devices.Add(deviceEntity); - SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + dbContext.Devices.Add(deviceEntity); + dbContext.SaveChanges(); } public void Remove(DeviceEntity deviceEntity) { - _dbContext.Devices.Remove(deviceEntity); - SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + dbContext.Devices.Remove(deviceEntity); + dbContext.SaveChanges(); } public DeviceEntity? Get(string id) { - return _dbContext.Devices.FirstOrDefault(d => d.Id == id); + using ArtemisDbContext dbContext = getContext(); + return dbContext.Devices.FirstOrDefault(d => d.Id == id); } public IEnumerable GetAll() { - return _dbContext.Devices; + using ArtemisDbContext dbContext = getContext(); + return dbContext.Devices; } - - public void SaveChanges() + + public void Save(DeviceEntity deviceEntity) { - _dbContext.SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + dbContext.Update(deviceEntity); + dbContext.SaveChanges(); + } + + public void SaveRange(IEnumerable deviceEntities) + { + using ArtemisDbContext dbContext = getContext(); + dbContext.UpdateRange(deviceEntities); + dbContext.SaveChanges(); } } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/EntryRepository.cs b/src/Artemis.Storage/Repositories/EntryRepository.cs index e378ace28..a901e637d 100644 --- a/src/Artemis.Storage/Repositories/EntryRepository.cs +++ b/src/Artemis.Storage/Repositories/EntryRepository.cs @@ -6,44 +6,44 @@ using Artemis.Storage.Repositories.Interfaces; namespace Artemis.Storage.Repositories; -internal class EntryRepository : IEntryRepository +internal class EntryRepository(Func getContext) : IEntryRepository { - private readonly ArtemisDbContext _dbContext; - - public EntryRepository(ArtemisDbContext dbContext) - { - _dbContext = dbContext; - } - public void Add(EntryEntity entryEntity) { - _dbContext.Entries.Add(entryEntity); - SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + dbContext.Entries.Add(entryEntity); + dbContext.SaveChanges(); } public void Remove(EntryEntity entryEntity) { - _dbContext.Entries.Remove(entryEntity); - SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + dbContext.Entries.Remove(entryEntity); + dbContext.SaveChanges(); } public EntryEntity? Get(Guid id) { - return _dbContext.Entries.FirstOrDefault(s => s.Id == id); + using ArtemisDbContext dbContext = getContext(); + return dbContext.Entries.FirstOrDefault(s => s.Id == id); } public EntryEntity? GetByEntryId(long entryId) { - return _dbContext.Entries.FirstOrDefault(s => s.EntryId == entryId); + using ArtemisDbContext dbContext = getContext(); + return dbContext.Entries.FirstOrDefault(s => s.EntryId == entryId); } public IEnumerable GetAll() { - return _dbContext.Entries; + using ArtemisDbContext dbContext = getContext(); + return dbContext.Entries; } - - public void SaveChanges() + + public void Save(EntryEntity entryEntity) { - _dbContext.SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + dbContext.Update(entryEntity); + dbContext.SaveChanges(); } } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IDeviceRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IDeviceRepository.cs index 960f61d66..f2a77e3d2 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IDeviceRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IDeviceRepository.cs @@ -9,5 +9,6 @@ public interface IDeviceRepository : IRepository void Remove(DeviceEntity deviceEntity); DeviceEntity? Get(string id); IEnumerable GetAll(); - void SaveChanges(); + void Save(DeviceEntity deviceEntity); + void SaveRange(IEnumerable deviceEntities); } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs index f1146de9f..46722068e 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IEntryRepository.cs @@ -11,5 +11,5 @@ public interface IEntryRepository : IRepository EntryEntity? Get(Guid id); EntryEntity? GetByEntryId(long entryId); IEnumerable GetAll(); - void SaveChanges(); + void Save(EntryEntity entryEntity); } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IPluginRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IPluginRepository.cs index 87e3e48e4..cb25caf5d 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IPluginRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IPluginRepository.cs @@ -5,10 +5,9 @@ namespace Artemis.Storage.Repositories.Interfaces; public interface IPluginRepository : IRepository { - void AddPlugin(PluginEntity pluginEntity); - PluginEntity? GetPluginByGuid(Guid pluginGuid); - void AddSetting(PluginSettingEntity pluginSettingEntity); + PluginEntity? GetPluginByPluginGuid(Guid pluginGuid); + void SaveSetting(PluginSettingEntity pluginSettingEntity); + void SavePlugin(PluginEntity pluginEntity); PluginSettingEntity? GetSettingByNameAndGuid(string name, Guid pluginGuid); void RemoveSettings(Guid pluginGuid); - void SaveChanges(); } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IProfileCategoryRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IProfileCategoryRepository.cs index cf3dccee6..533e8990e 100644 --- a/src/Artemis.Storage/Repositories/Interfaces/IProfileCategoryRepository.cs +++ b/src/Artemis.Storage/Repositories/Interfaces/IProfileCategoryRepository.cs @@ -12,5 +12,6 @@ public interface IProfileCategoryRepository : IRepository List GetAll(); ProfileCategoryEntity? Get(Guid id); bool IsUnique(string name, Guid? id); - void SaveChanges(); + void Save(ProfileCategoryEntity profileCategoryEntity); + void SaveRange(List profileCategoryEntities); } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IProfileRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IProfileRepository.cs new file mode 100644 index 000000000..bc26090a5 --- /dev/null +++ b/src/Artemis.Storage/Repositories/Interfaces/IProfileRepository.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using Artemis.Storage.Entities.Profile; + +namespace Artemis.Storage.Repositories.Interfaces; + +public interface IProfileRepository : IRepository +{ + void Add(ProfileContainerEntity profileContainerEntity); + void Remove(ProfileContainerEntity profileContainerEntity); + void Save(ProfileContainerEntity profileContainerEntity); + void SaveRange(List profileContainerEntities); + void MigrateProfiles(); + void MigrateProfile(JsonObject? configurationJson, JsonObject? profileJson); +} \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/Interfaces/IReleaseRepository.cs b/src/Artemis.Storage/Repositories/Interfaces/IReleaseRepository.cs new file mode 100644 index 000000000..9404bf8dd --- /dev/null +++ b/src/Artemis.Storage/Repositories/Interfaces/IReleaseRepository.cs @@ -0,0 +1,9 @@ +using Artemis.Storage.Entities.General; + +namespace Artemis.Storage.Repositories.Interfaces; + +public interface IReleaseRepository : IRepository +{ + bool SaveVersionInstallDate(string version); + ReleaseEntity? GetPreviousInstalledVersion(); +} \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/PluginRepository.cs b/src/Artemis.Storage/Repositories/PluginRepository.cs index 8c53d776c..abb335893 100644 --- a/src/Artemis.Storage/Repositories/PluginRepository.cs +++ b/src/Artemis.Storage/Repositories/PluginRepository.cs @@ -6,44 +6,39 @@ using Microsoft.EntityFrameworkCore; namespace Artemis.Storage.Repositories; -internal class PluginRepository : IPluginRepository +internal class PluginRepository(Func getContext) : IPluginRepository { - private readonly ArtemisDbContext _dbContext; - - public PluginRepository(ArtemisDbContext dbContext) + public PluginEntity? GetPluginByPluginGuid(Guid pluginGuid) { - _dbContext = dbContext; - } - - public void AddPlugin(PluginEntity pluginEntity) - { - _dbContext.Plugins.Add(pluginEntity); - SaveChanges(); - } - - public PluginEntity? GetPluginByGuid(Guid pluginGuid) - { - return _dbContext.Plugins.Include(p => p.Features).FirstOrDefault(p => p.Id == pluginGuid); - } - - public void AddSetting(PluginSettingEntity pluginSettingEntity) - { - _dbContext.PluginSettings.Add(pluginSettingEntity); - SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + return dbContext.Plugins.Include(p => p.Features).FirstOrDefault(p => p.PluginGuid == pluginGuid); } public PluginSettingEntity? GetSettingByNameAndGuid(string name, Guid pluginGuid) { - return _dbContext.PluginSettings.FirstOrDefault(p => p.Name == name && p.PluginGuid == pluginGuid); + using ArtemisDbContext dbContext = getContext(); + return dbContext.PluginSettings.FirstOrDefault(p => p.Name == name && p.PluginGuid == pluginGuid); } - + public void RemoveSettings(Guid pluginGuid) { - _dbContext.PluginSettings.RemoveRange(_dbContext.PluginSettings.Where(s => s.PluginGuid == pluginGuid)); + using ArtemisDbContext dbContext = getContext(); + dbContext.PluginSettings.RemoveRange(dbContext.PluginSettings.Where(s => s.PluginGuid == pluginGuid)); + dbContext.SaveChanges(); } - public void SaveChanges() + public void SaveSetting(PluginSettingEntity pluginSettingEntity) { - _dbContext.SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + dbContext.PluginSettings.Update(pluginSettingEntity); + dbContext.SaveChanges(); } + + public void SavePlugin(PluginEntity pluginEntity) + { + using ArtemisDbContext dbContext = getContext(); + dbContext.Update(pluginEntity); + dbContext.SaveChanges(); + } + } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/ProfileCategoryRepository.cs b/src/Artemis.Storage/Repositories/ProfileCategoryRepository.cs index 7d0ef11bc..90e53c731 100644 --- a/src/Artemis.Storage/Repositories/ProfileCategoryRepository.cs +++ b/src/Artemis.Storage/Repositories/ProfileCategoryRepository.cs @@ -7,47 +7,63 @@ using Microsoft.EntityFrameworkCore; namespace Artemis.Storage.Repositories; -internal class ProfileCategoryRepository : IProfileCategoryRepository +internal class ProfileCategoryRepository(Func getContext, IProfileRepository profileRepository) : IProfileCategoryRepository { - private readonly ArtemisDbContext _dbContext; - - public ProfileCategoryRepository(ArtemisDbContext dbContext) - { - _dbContext = dbContext; - } + private bool _migratedProfiles; public void Add(ProfileCategoryEntity profileCategoryEntity) { - _dbContext.ProfileCategories.Add(profileCategoryEntity); - SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + dbContext.ProfileCategories.Add(profileCategoryEntity); + dbContext.SaveChanges(); } public void Remove(ProfileCategoryEntity profileCategoryEntity) { - _dbContext.ProfileCategories.Remove(profileCategoryEntity); - SaveChanges(); + using ArtemisDbContext dbContext = getContext(); + dbContext.ProfileCategories.Remove(profileCategoryEntity); + dbContext.SaveChanges(); } public List GetAll() { - return _dbContext.ProfileCategories.Include(c => c.ProfileConfigurations).ToList(); + if (!_migratedProfiles) + { + profileRepository.MigrateProfiles(); + _migratedProfiles = true; + } + + using ArtemisDbContext dbContext = getContext(); + return dbContext.ProfileCategories.Include(c => c.ProfileConfigurations).ToList(); } public ProfileCategoryEntity? Get(Guid id) { - return _dbContext.ProfileCategories.Include(c => c.ProfileConfigurations).FirstOrDefault(c => c.Id == id); + using ArtemisDbContext dbContext = getContext(); + return dbContext.ProfileCategories.Include(c => c.ProfileConfigurations).FirstOrDefault(c => c.Id == id); + } + + public void Save(ProfileCategoryEntity profileCategoryEntity) + { + using ArtemisDbContext dbContext = getContext(); + dbContext.Update(profileCategoryEntity); + dbContext.SaveChanges(); + } + + public void SaveRange(List profileCategoryEntities) + { + using ArtemisDbContext dbContext = getContext(); + dbContext.UpdateRange(profileCategoryEntities); + dbContext.SaveChanges(); } public bool IsUnique(string name, Guid? id) { + using ArtemisDbContext dbContext = getContext(); + name = name.Trim(); - if (id == null) - return _dbContext.ProfileCategories.Any(p => p.Name == name); - return _dbContext.ProfileCategories.Any(p => p.Name == name && p.Id != id.Value); - } - - public void SaveChanges() - { - _dbContext.SaveChanges(); + return id == null + ? dbContext.ProfileCategories.Any(p => p.Name == name) + : dbContext.ProfileCategories.Any(p => p.Name == name && p.Id != id.Value); } } \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/ProfileRepository.cs b/src/Artemis.Storage/Repositories/ProfileRepository.cs new file mode 100644 index 000000000..78c9ca6a0 --- /dev/null +++ b/src/Artemis.Storage/Repositories/ProfileRepository.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Nodes; +using Artemis.Storage.Entities; +using Artemis.Storage.Entities.Profile; +using Artemis.Storage.Exceptions; +using Artemis.Storage.Migrations; +using Artemis.Storage.Repositories.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace Artemis.Storage.Repositories; + +public class ProfileRepository(Func getContext, List profileMigrators) : IProfileRepository +{ + public void Add(ProfileContainerEntity profileContainerEntity) + { + using ArtemisDbContext dbContext = getContext(); + dbContext.ProfileContainers.Add(profileContainerEntity); + dbContext.SaveChanges(); + } + + public void Remove(ProfileContainerEntity profileContainerEntity) + { + using ArtemisDbContext dbContext = getContext(); + dbContext.ProfileContainers.Remove(profileContainerEntity); + dbContext.SaveChanges(); + } + + public void Save(ProfileContainerEntity profileContainerEntity) + { + using ArtemisDbContext dbContext = getContext(); + dbContext.Update(profileContainerEntity); + dbContext.SaveChanges(); + } + + public void SaveRange(List profileContainerEntities) + { + using ArtemisDbContext dbContext = getContext(); + dbContext.UpdateRange(profileContainerEntities); + dbContext.SaveChanges(); + } + + public void MigrateProfiles() + { + using ArtemisDbContext dbContext = getContext(); + int max = profileMigrators.Max(m => m.Version); + + // Query the ProfileContainerEntity table directly, grabbing the ID, profile, and configuration + List containers = dbContext.Database + .SqlQueryRaw("SELECT Id, Profile, ProfileConfiguration FROM ProfileContainers WHERE json_extract(ProfileConfiguration, '$.Version') < {0}", max) + .ToList(); + + foreach (RawProfileContainer rawProfileContainer in containers) + { + JsonObject? profileConfiguration = JsonNode.Parse(rawProfileContainer.ProfileConfiguration)?.AsObject(); + JsonObject? profile = JsonNode.Parse(rawProfileContainer.Profile)?.AsObject(); + + if (profileConfiguration == null || profile == null) + throw new ArtemisStorageException("Failed to parse profile or profile configuration"); + + MigrateProfile(profileConfiguration, profile); + rawProfileContainer.Profile = profile.ToString(); + rawProfileContainer.ProfileConfiguration = profileConfiguration.ToString(); + + // Write the updated containers back to the database + dbContext.Database.ExecuteSqlRaw( + "UPDATE ProfileContainers SET Profile = {0}, ProfileConfiguration = {1} WHERE Id = {2}", + rawProfileContainer.Profile, + rawProfileContainer.ProfileConfiguration, + rawProfileContainer.Id); + } + } + + public void MigrateProfile(JsonObject? configurationJson, JsonObject? profileJson) + { + if (configurationJson == null || profileJson == null) + return; + + configurationJson["Version"] ??= 0; + + foreach (IProfileMigration profileMigrator in profileMigrators.OrderBy(m => m.Version)) + { + if (profileMigrator.Version <= configurationJson["Version"]!.GetValue()) + continue; + + profileMigrator.Migrate(configurationJson, profileJson); + configurationJson["Version"] = profileMigrator.Version; + } + } +} \ No newline at end of file diff --git a/src/Artemis.Storage/Repositories/ReleaseRepository.cs b/src/Artemis.Storage/Repositories/ReleaseRepository.cs index d7e320919..16f5dd7a6 100644 --- a/src/Artemis.Storage/Repositories/ReleaseRepository.cs +++ b/src/Artemis.Storage/Repositories/ReleaseRepository.cs @@ -5,34 +5,24 @@ using Artemis.Storage.Repositories.Interfaces; namespace Artemis.Storage.Repositories; -public class ReleaseRepository : IReleaseRepository +public class ReleaseRepository(Func getContext) : IReleaseRepository { - private readonly ArtemisDbContext _dbContext; - - public ReleaseRepository(ArtemisDbContext dbContext) - { - _dbContext = dbContext; - } - public bool SaveVersionInstallDate(string version) { - ReleaseEntity? release = _dbContext.Releases.FirstOrDefault(r => r.Version == version); + using ArtemisDbContext dbContext = getContext(); + + ReleaseEntity? release = dbContext.Releases.FirstOrDefault(r => r.Version == version); if (release != null) return false; - _dbContext.Releases.Add(new ReleaseEntity {Version = version, InstalledAt = DateTimeOffset.UtcNow}); - _dbContext.SaveChanges(); + dbContext.Releases.Add(new ReleaseEntity {Version = version, InstalledAt = DateTimeOffset.UtcNow}); + dbContext.SaveChanges(); return true; } public ReleaseEntity? GetPreviousInstalledVersion() { - return _dbContext.Releases.OrderByDescending(r => r.InstalledAt).Skip(1).FirstOrDefault(); + using ArtemisDbContext dbContext = getContext(); + return dbContext.Releases.OrderByDescending(r => r.InstalledAt).Skip(1).FirstOrDefault(); } -} - -public interface IReleaseRepository : IRepository -{ - bool SaveVersionInstallDate(string version); - ReleaseEntity? GetPreviousInstalledVersion(); } \ No newline at end of file diff --git a/src/Artemis.UI.Linux/App.axaml.cs b/src/Artemis.UI.Linux/App.axaml.cs index 88f0f8179..dbba1fb2f 100644 --- a/src/Artemis.UI.Linux/App.axaml.cs +++ b/src/Artemis.UI.Linux/App.axaml.cs @@ -1,5 +1,6 @@ using System; using Artemis.Core.Services; +using Artemis.Storage.Legacy; using Artemis.UI.Linux.DryIoc; using Artemis.UI.Linux.Providers.Input; using Avalonia; @@ -20,7 +21,10 @@ public class App : Application public override void Initialize() { _container = ArtemisBootstrapper.Bootstrap(this, c => c.RegisterProviders()); + Program.CreateLogger(_container); + LegacyMigrationService.MigrateToSqlite(_container); + RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; AvaloniaXamlLoader.Load(this); } diff --git a/src/Artemis.UI.Linux/Artemis.UI.Linux.csproj b/src/Artemis.UI.Linux/Artemis.UI.Linux.csproj index c41b62a40..ed8f08fda 100644 --- a/src/Artemis.UI.Linux/Artemis.UI.Linux.csproj +++ b/src/Artemis.UI.Linux/Artemis.UI.Linux.csproj @@ -17,6 +17,7 @@ + diff --git a/src/Artemis.UI.MacOS/App.axaml.cs b/src/Artemis.UI.MacOS/App.axaml.cs index 0d81b318d..800bb523f 100644 --- a/src/Artemis.UI.MacOS/App.axaml.cs +++ b/src/Artemis.UI.MacOS/App.axaml.cs @@ -1,3 +1,4 @@ +using Artemis.Storage.Legacy; using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; @@ -14,7 +15,10 @@ public class App : Application public override void Initialize() { _container = ArtemisBootstrapper.Bootstrap(this); + Program.CreateLogger(_container); + LegacyMigrationService.MigrateToSqlite(_container); + RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; AvaloniaXamlLoader.Load(this); } diff --git a/src/Artemis.UI.MacOS/Artemis.UI.MacOS.csproj b/src/Artemis.UI.MacOS/Artemis.UI.MacOS.csproj index d762afde1..f322b73d7 100644 --- a/src/Artemis.UI.MacOS/Artemis.UI.MacOS.csproj +++ b/src/Artemis.UI.MacOS/Artemis.UI.MacOS.csproj @@ -16,6 +16,7 @@ + \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj index bf6734a2a..42faecb23 100644 --- a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj +++ b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj @@ -21,6 +21,7 @@ + diff --git a/src/Artemis.UI.Windows/App.axaml.cs b/src/Artemis.UI.Windows/App.axaml.cs index 41ed8e923..66d5aac1b 100644 --- a/src/Artemis.UI.Windows/App.axaml.cs +++ b/src/Artemis.UI.Windows/App.axaml.cs @@ -7,6 +7,7 @@ using System.Net.Http; using System.Threading; using Artemis.Core; using Artemis.Core.Services; +using Artemis.Storage.Legacy; using Artemis.UI.Windows.DryIoc; using Artemis.UI.Windows.Providers.Input; using Avalonia; @@ -34,7 +35,10 @@ public class App : Application } _container = ArtemisBootstrapper.Bootstrap(this, c => c.RegisterProviders()); + Program.CreateLogger(_container); + LegacyMigrationService.MigrateToSqlite(_container); + RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; AvaloniaXamlLoader.Load(this); } diff --git a/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj b/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj index 52a121156..f74f2bd4b 100644 --- a/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj +++ b/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj @@ -30,6 +30,7 @@ + diff --git a/src/Artemis.UI/Services/Updating/UpdateService.cs b/src/Artemis.UI/Services/Updating/UpdateService.cs index deb6484ea..a6259db37 100644 --- a/src/Artemis.UI/Services/Updating/UpdateService.cs +++ b/src/Artemis.UI/Services/Updating/UpdateService.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; using Artemis.Storage.Repositories; +using Artemis.Storage.Repositories.Interfaces; using Artemis.UI.Exceptions; using Artemis.UI.Shared.Services.MainWindow; using Artemis.WebClient.Updating; diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs index 4ee9e0cb5..1219f84d6 100644 --- a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs @@ -76,7 +76,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler // Find the profile if still there ProfileConfiguration? profile = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == profileId); if (profile != null) - _profileService.DeleteProfile(profile); + _profileService.RemoveProfileConfiguration(profile); // Remove the release _workshopService.RemoveInstalledEntry(installedEntry); diff --git a/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs index 3da255d12..95b90ccc5 100644 --- a/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs +++ b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs @@ -171,12 +171,7 @@ public class WorkshopService : IWorkshopService public void SaveInstalledEntry(InstalledEntry entry) { entry.Save(); - - // Upsert for plebs - if (entry.Entity.Id == Guid.Empty) - _entryRepository.Add(entry.Entity); - else - _entryRepository.SaveChanges(); + _entryRepository.Save(entry.Entity); } /// diff --git a/src/Artemis.sln b/src/Artemis.sln index 984eb7997..7f7a038f0 100644 --- a/src/Artemis.sln +++ b/src/Artemis.sln @@ -29,7 +29,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Build.props = Directory.Build.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Storage.Migrator", "Artemis.Storage.Migrator\Artemis.Storage.Migrator.csproj", "{D7B0966D-774A-40E4-9455-00C1261ACB6A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Storage.Legacy", "Artemis.Storage.Legacy\Artemis.Storage.Legacy.csproj", "{D7B0966D-774A-40E4-9455-00C1261ACB6A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 3c9d036db..f997dd00e 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -25,12 +25,13 @@ + - +