diff --git a/Rdmp.Core/CommandExecution/AtomicCommandFactory.cs b/Rdmp.Core/CommandExecution/AtomicCommandFactory.cs index e2e35c627b..382df303d1 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommandFactory.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommandFactory.cs @@ -502,39 +502,55 @@ public IEnumerable CreateCommands(object o) if (Is(o, out LoadMetadata lmd)) { - yield return new ExecuteCommandExportObjectsToFile(_activator, new IMapsDirectlyToDatabaseTable[] { lmd }); - - yield return new ExecuteCommandOverrideRawServer(_activator, lmd); - yield return new ExecuteCommandCreateNewLoadMetadata(_activator); - var reservedTest = lmd.AllowReservedPrefix ? "Drop" : "Allow"; - yield return new ExecuteCommandToggleAllowReservedPrefixForLoadMetadata(lmd) + if (lmd.RootLoadMetadata_ID is null) { - OverrideCommandName=$"{reservedTest} Reserved Prefix Columns" - }; + yield return new ExecuteCommandExportObjectsToFile(_activator, new IMapsDirectlyToDatabaseTable[] { lmd }); - yield return new ExecuteCommandSetGlobalDleIgnorePattern(_activator) { SuggestedCategory = Advanced }; - yield return new ExecuteCommandSetIgnoredColumns(_activator, lmd) { SuggestedCategory = Advanced }; - yield return new ExecuteCommandSetIgnoredColumns(_activator, lmd, null) - { OverrideCommandName = "Clear Ignored Columns", SuggestedCategory = Advanced }; + yield return new ExecuteCommandOverrideRawServer(_activator, lmd); + yield return new ExecuteCommandCreateNewLoadMetadata(_activator); + var reservedTest = lmd.AllowReservedPrefix ? "Drop" : "Allow"; + yield return new ExecuteCommandToggleAllowReservedPrefixForLoadMetadata(lmd) + { + OverrideCommandName = $"{reservedTest} Reserved Prefix Columns" + }; + yield return new ExecuteCommandCreateLoadMetadataVersion(_activator, lmd) + { + OverrideCommandName = "Save Version" + }; + yield return new ExecuteCommandCloneLoadMetadata(_activator, lmd) + { + OverrideCommandName = "Clone Load Metadata" + }; - yield return new ExecuteCommandSetExtendedProperty(_activator, new[] { lmd }, - ExtendedProperty.PersistentRaw, null) - { - OverrideCommandName = "Persistent RAW", - PromptForValue = true, - PromptForValueTaskDescription = ExtendedProperty.PersistentRawDescription, - SuggestedCategory = Advanced - }; + yield return new ExecuteCommandSetGlobalDleIgnorePattern(_activator) { SuggestedCategory = Advanced }; + yield return new ExecuteCommandSetIgnoredColumns(_activator, lmd) { SuggestedCategory = Advanced }; + yield return new ExecuteCommandSetIgnoredColumns(_activator, lmd, null) + { OverrideCommandName = "Clear Ignored Columns", SuggestedCategory = Advanced }; - yield return new ExecuteCommandSet(_activator, lmd, - typeof(LoadMetadata).GetProperty(nameof(LoadMetadata.IgnoreTrigger))) + yield return new ExecuteCommandSetExtendedProperty(_activator, new[] { lmd }, + ExtendedProperty.PersistentRaw, null) + { + OverrideCommandName = "Persistent RAW", + PromptForValue = true, + PromptForValueTaskDescription = ExtendedProperty.PersistentRawDescription, + SuggestedCategory = Advanced + }; + + yield return new ExecuteCommandSet(_activator, lmd, + typeof(LoadMetadata).GetProperty(nameof(LoadMetadata.IgnoreTrigger))) + { + OverrideCommandName = $"Ignore Trigger (Current value:{lmd.IgnoreTrigger})", + SuggestedCategory = Advanced + }; + } + else { - OverrideCommandName = $"Ignore Trigger (Current value:{lmd.IgnoreTrigger})", - SuggestedCategory = Advanced - }; + yield return new ExecuteCommandRestoreLoadMetadataVersion(_activator, lmd) + { + OverrideCommandName = "Restore Version"}; + } } - if (Is(o, out LoadMetadataScheduleNode scheduleNode)) yield return new ExecuteCommandCreateNewLoadProgress(_activator, scheduleNode.LoadMetadata); diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCloneLoadMetadata.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCloneLoadMetadata.cs new file mode 100644 index 0000000000..aebb36fee2 --- /dev/null +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCloneLoadMetadata.cs @@ -0,0 +1,31 @@ +using Rdmp.Core.Curation.Data.DataLoad; +using Rdmp.Core.Curation.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Rdmp.Core.CommandExecution.AtomicCommands; + +public class ExecuteCommandCloneLoadMetadata : BasicCommandExecution +{ + private LoadMetadata _loadMetadata; + private IBasicActivateItems _activator; + public ExecuteCommandCloneLoadMetadata(IBasicActivateItems activator,[DemandsInitialization("The LoadMetadata to clone")] LoadMetadata loadMetadata) + { + + _loadMetadata = loadMetadata; + _activator = activator; + } + + public override void Execute() + { + base.Execute(); + var lmd = _loadMetadata.Clone(); + lmd.Name = lmd.Name + " (Clone)"; + lmd.SaveToDatabase(); + _activator.Publish(lmd); + + } +} diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateLoadMetadataVersion.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateLoadMetadataVersion.cs index f5c6cc87d8..85b410bb9e 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateLoadMetadataVersion.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateLoadMetadataVersion.cs @@ -11,10 +11,12 @@ namespace Rdmp.Core.CommandExecution.AtomicCommands; public class ExecuteCommandCreateLoadMetadataVersion: BasicCommandExecution { private LoadMetadata _loadMetadata; - public ExecuteCommandCreateLoadMetadataVersion([DemandsInitialization("The LoadMetadata to update")] LoadMetadata loadMetadata) + private IBasicActivateItems _activator; + public ExecuteCommandCreateLoadMetadataVersion(IBasicActivateItems activator,[DemandsInitialization("The LoadMetadata to version")] LoadMetadata loadMetadata) { _loadMetadata = loadMetadata; + _activator = activator; } public override void Execute() @@ -24,7 +26,8 @@ public override void Execute() { throw new Exception("Must Use Root LoadMetadata to create Version"); } - var lmd = _loadMetadata.Clone(); + var lmd = _loadMetadata.SaveNewVersion(); lmd.SaveToDatabase(); + _activator.Publish(lmd); } } diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewClassBasedProcessTask.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewClassBasedProcessTask.cs index 9c2639e310..b4afaa4220 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewClassBasedProcessTask.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewClassBasedProcessTask.cs @@ -72,7 +72,6 @@ public override void Execute() else return; } - _loadMetadata.Clone(); var newTask = new ProcessTask(BasicActivator.RepositoryLocator.CatalogueRepository, _loadMetadata, _loadStage) { Path = _type.FullName, diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewFileBasedProcessTask.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewFileBasedProcessTask.cs index 60406d1a73..cc42d6cfcf 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewFileBasedProcessTask.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewFileBasedProcessTask.cs @@ -96,7 +96,6 @@ public override void Execute() throw new ArgumentOutOfRangeException($"Unexpected _taskType:{_taskType}"); } } - _loadMetadata.Clone(); var task = new ProcessTask((ICatalogueRepository)_loadMetadata.Repository, _loadMetadata, _loadStage) { ProcessTaskType = _taskType, diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandDisableOrEnable.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandDisableOrEnable.cs index e33b9b0545..6965c81c10 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandDisableOrEnable.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandDisableOrEnable.cs @@ -74,18 +74,8 @@ public override void Execute() foreach (var d in _targets) { - var x = d.GetType(); - if (d.GetType() == typeof(ProcessTask)) - { - var newVersion = (IDisableable)((IVersionable)d).SaveNewVersion(); - newVersion.IsDisabled = true; - newVersion.SaveToDatabase(); - } - else - { - d.IsDisabled = !d.IsDisabled; - d.SaveToDatabase(); - } + d.IsDisabled = !d.IsDisabled; + d.SaveToDatabase(); } var toRefresh = _targets.FirstOrDefault(); diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandRestoreLoadMetadataVersion.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandRestoreLoadMetadataVersion.cs new file mode 100644 index 0000000000..e9354c6175 --- /dev/null +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandRestoreLoadMetadataVersion.cs @@ -0,0 +1,48 @@ +using Rdmp.Core.Curation.Data.DataLoad; +using Rdmp.Core.Curation.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Org.BouncyCastle.Pqc.Crypto.Lms; + +namespace Rdmp.Core.CommandExecution.AtomicCommands; + +public class ExecuteCommandRestoreLoadMetadataVersion : BasicCommandExecution +{ + private LoadMetadata _loadMetadata; + private IBasicActivateItems _activator; + public ExecuteCommandRestoreLoadMetadataVersion(IBasicActivateItems activator, [DemandsInitialization("The LoadMetadata to version")] LoadMetadata loadMetadata) + { + + _loadMetadata = loadMetadata; + _activator = activator; + } + + public override void Execute() + { + if (!_activator.YesNo("Replace root Load Metadata with this configuration?","Resotre Load Metadata Version")) return; + base.Execute(); + if (_loadMetadata.RootLoadMetadata_ID is null) + { + throw new Exception("Must Use a versioned LoadMetadata to create Version"); + } + LoadMetadata lmd = (LoadMetadata)_activator.RepositoryLocator.CatalogueRepository.GetObjectByID(typeof(LoadMetadata), (int)_loadMetadata.RootLoadMetadata_ID); + if (lmd is null) + { + throw new Exception("Could not find root load metadata"); + + } + foreach (ProcessTask task in lmd.ProcessTasks) + { + task.DeleteInDatabase(); + } + foreach(ProcessTask task in _loadMetadata.ProcessTasks) + { + task.Clone(lmd); + } + lmd.SaveToDatabase(); + _activator.Publish(lmd); + } +} diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandToggleAllowReservedPrefixForLoadMetadata.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandToggleAllowReservedPrefixForLoadMetadata.cs index 53e68eb461..16aba34c68 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandToggleAllowReservedPrefixForLoadMetadata.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandToggleAllowReservedPrefixForLoadMetadata.cs @@ -24,7 +24,6 @@ public ExecuteCommandToggleAllowReservedPrefixForLoadMetadata([DemandsInitializa public override void Execute() { base.Execute(); - _loadMetadata.Clone(); _loadMetadata.AllowReservedPrefix = !_loadMetadata.AllowReservedPrefix; _loadMetadata.SaveToDatabase(); } diff --git a/Rdmp.Core/Curation/Data/DataLoad/LoadMetadata.cs b/Rdmp.Core/Curation/Data/DataLoad/LoadMetadata.cs index d3bec51560..d78da70a8a 100644 --- a/Rdmp.Core/Curation/Data/DataLoad/LoadMetadata.cs +++ b/Rdmp.Core/Curation/Data/DataLoad/LoadMetadata.cs @@ -292,6 +292,10 @@ public LoadMetadata Clone() }; lmd.SaveToDatabase(); //link to catalogue + foreach(var catalogue in this.GetAllCatalogues()) + { + lmd.LinkToCatalogue(catalogue); + } //process task var pts = CatalogueRepository.GetAllObjectsWhere("LoadMetadata_ID", this.ID); foreach(ProcessTask pt in pts) @@ -510,6 +514,7 @@ public DatabaseEntity SaveNewVersion() { var lmd = this.Clone(); lmd.RootLoadMetadata_ID = this.RootLoadMetadata_ID != null ? this.RootLoadMetadata_ID : this.ID; + lmd.Name = $"{this.Name} - {DateTime.Now}"; lmd.SaveToDatabase(); return lmd; } diff --git a/Rdmp.Core/Curation/Data/DataLoad/ProcessTask.cs b/Rdmp.Core/Curation/Data/DataLoad/ProcessTask.cs index 300d0d61ef..1f1bf8825a 100644 --- a/Rdmp.Core/Curation/Data/DataLoad/ProcessTask.cs +++ b/Rdmp.Core/Curation/Data/DataLoad/ProcessTask.cs @@ -163,7 +163,6 @@ public ProcessTask(ICatalogueRepository repository, ILoadMetadata parent, LoadSt repository.InsertAndHydrate(this, new Dictionary { { "LoadMetadata_ID", parent.RootLoadMetadata_ID??parent.ID }, - { "LoadMetadataVersion", parent.RootLoadMetadata_ID != null?parent.ID:0 }, { "ProcessTaskType", ProcessTaskType.Executable.ToString() }, { "LoadStage", stage }, { "Name", $"New Process{Guid.NewGuid()}" }, @@ -186,7 +185,6 @@ public ProcessTask(ICatalogueRepository repository, ILoadMetadata parent, LoadSt repository.InsertAndHydrate(this, new Dictionary { { "LoadMetadata_ID", parent.RootLoadMetadata_ID??parent.ID }, - { "LoadMetadataVersion", parent.RootLoadMetadata_ID != null?parent.ID:0 }, { "ProcessTaskType", ProcessTaskType.Executable.ToString() }, { "LoadStage", stage }, { "Name", $"New Process{Guid.NewGuid()}" }, diff --git a/Rdmp.Core/Icons/IconProvision/CatalogueIcons.resx b/Rdmp.Core/Icons/IconProvision/CatalogueIcons.resx index 6abf0c1c75..db264af676 100644 --- a/Rdmp.Core/Icons/IconProvision/CatalogueIcons.resx +++ b/Rdmp.Core/Icons/IconProvision/CatalogueIcons.resx @@ -262,6 +262,9 @@ ..\CatalogueFolder.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\CatalogueFolder.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\CatalogueItem.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/Rdmp.Core/Icons/IconProvision/RDMPConcept.cs b/Rdmp.Core/Icons/IconProvision/RDMPConcept.cs index 3fc3fbb0d4..b3988b6401 100644 --- a/Rdmp.Core/Icons/IconProvision/RDMPConcept.cs +++ b/Rdmp.Core/Icons/IconProvision/RDMPConcept.cs @@ -122,6 +122,7 @@ public enum RDMPConcept AllProcessTasksUsedByLoadMetadataNode, AllCataloguesUsedByLoadMetadataNode, LoadMetadataScheduleNode, + LoadMetadataVersionNode, Logging, GetFilesStage, diff --git a/Rdmp.Core/Providers/CatalogueChildProvider.cs b/Rdmp.Core/Providers/CatalogueChildProvider.cs index 091f1616ae..c8988d0374 100644 --- a/Rdmp.Core/Providers/CatalogueChildProvider.cs +++ b/Rdmp.Core/Providers/CatalogueChildProvider.cs @@ -397,7 +397,7 @@ public CatalogueChildProvider(ICatalogueRepository repository, IChildProvider[] ReportProgress("Build Catalogue Folder Root"); - LoadMetadataRootFolder = FolderHelper.BuildFolderTree(AllLoadMetadatas); + LoadMetadataRootFolder = FolderHelper.BuildFolderTree(AllLoadMetadatas.Where(lmd => lmd.RootLoadMetadata_ID is null).ToArray()); AddChildren(LoadMetadataRootFolder, new DescendancyList(LoadMetadataRootFolder)); CohortIdentificationConfigurationRootFolder = @@ -856,7 +856,7 @@ private void AddChildren(FolderNode folder, DescendancyList descen AddChildren(child, descendancy.Add(child)); //add loads in folder - foreach (var lmd in folder.ChildObjects) AddChildren(lmd, descendancy.Add(lmd)); + foreach (var lmd in folder.ChildObjects.Where(lmd => lmd.RootLoadMetadata_ID == null).ToArray()) AddChildren(lmd, descendancy.Add(lmd)); // Children are the folders + objects AddToDictionaries(new HashSet( folder.ChildFolders.Cast() @@ -929,6 +929,10 @@ private void AddChildren(LoadMetadata lmd, DescendancyList descendancy) AddChildren(processTasksNode, descendancy.Add(processTasksNode)); childObjects.Add(processTasksNode); + var versionsNode = new LoadMetadataVersionNode(lmd); + AddChildren(versionsNode, descendancy.Add(versionsNode)); + childObjects.Add(versionsNode); + childObjects.Add(new LoadDirectoryNode(lmd)); AddToDictionaries(new HashSet(childObjects), descendancy); @@ -1017,6 +1021,12 @@ private void AddChildren(ProcessTask procesTask, DescendancyList descendancy) AddToDictionaries(new HashSet(args), descendancy); } + private void AddChildren(LoadMetadataVersionNode LoadMetadataVersionNode, DescendancyList descendancy) + { + LoadMetadataVersionNode.LoadMetadataVersions = AllLoadMetadatas.Where(lmd => lmd.RootLoadMetadata_ID == LoadMetadataVersionNode.LoadMetadata.ID).ToList(); + AddToDictionaries(LoadMetadataVersionNode.LoadMetadataVersions.Cast().ToHashSet(), descendancy); + } + private void AddChildren(AllCataloguesUsedByLoadMetadataNode allCataloguesUsedByLoadMetadataNode, DescendancyList descendancy) { diff --git a/Rdmp.Core/Providers/Nodes/LoadMetadataNodes/LoadMetadataVersionNodes.cs b/Rdmp.Core/Providers/Nodes/LoadMetadataNodes/LoadMetadataVersionNodes.cs new file mode 100644 index 0000000000..a6c1e8e402 --- /dev/null +++ b/Rdmp.Core/Providers/Nodes/LoadMetadataNodes/LoadMetadataVersionNodes.cs @@ -0,0 +1,49 @@ +// Copyright (c) The University of Dundee 2018-2019 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using System; +using System.Collections.Generic; +using Rdmp.Core.Curation.Data; +using Rdmp.Core.Curation.Data.Cohort; +using Rdmp.Core.Curation.Data.DataLoad; + +namespace Rdmp.Core.Providers.Nodes.LoadMetadataNodes; + +/// +/// Collection of all the s which are currently associated with a given . This governs +/// which tables are created in RAW=>STAGING=>LIVE. +/// +public class LoadMetadataVersionNode : Node, IOrderable +{ + public LoadMetadata LoadMetadata { get; } + + public int Order + { + get => 1; + set { } + } + + public List LoadMetadataVersions { get; set; } + + public LoadMetadataVersionNode(LoadMetadata lmd) + { + LoadMetadata = lmd; + } + + public override string ToString() => "Versions"; + + protected bool Equals(LoadMetadataVersionNode other) => Equals(LoadMetadata, other.LoadMetadata); + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((LoadMetadataVersionNode)obj); + } + + public override int GetHashCode() => HashCode.Combine(LoadMetadata); +} \ No newline at end of file diff --git a/Rdmp.Core/ReusableLibraryCode/IVersionable.cs b/Rdmp.Core/ReusableLibraryCode/IVersionable.cs new file mode 100644 index 0000000000..53011c2972 --- /dev/null +++ b/Rdmp.Core/ReusableLibraryCode/IVersionable.cs @@ -0,0 +1,18 @@ +using Rdmp.Core.Curation.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Rdmp.Core.ReusableLibraryCode; + +internal interface IVersionable +{ + + /// + /// + /// + /// + DatabaseEntity SaveNewVersion(); +}