diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000000..350da421cc
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**RDMP Version**
+Displayed in the task bar of the software e.g. v4.1.5
+
+**Error with Stack Trace**
+```
+If applicable, paste the entire stack trace here, leave the triple quotes (```)
+```
+
+**Database Engine**
+Sql Server, Oracle, MySql or Postgres.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.travis.yml b/.travis.yml
index 4771951394..10c6fb78c8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,18 +1,35 @@
-language: csharp
-mono: none
-dotnet: 2.2.100
+language: generic
+dist: bionic
+os: linux
addons:
postgresql: "10"
+ apt:
+ packages:
+ sources:
+ - sourceline: 'deb [arch=amd64] https://packages.microsoft.com/ubuntu/18.04/prod bionic main'
+ key_url: 'https://packages.microsoft.com/keys/microsoft.asc'
+ - sourceline: 'deb [arch=amd64,arm64,armhf] https://packages.microsoft.com/ubuntu/18.04/mssql-server-2019 bionic main'
services:
- postgresql
- mysql
+env:
+ global:
+ - MSSQL_SA_PASSWORD="YourStrong!Passw0rd"
+ - ACCEPT_EULA=Y
+ - MSSQL_PID='developer'
+
+cache:
+ directories:
+ - $HOME/.local/share/NuGet/
+ - $HOME/.nuget
+
before_script:
-- sudo docker run --name=mssql-server-linux-latest -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=YourStrong!Passw0rd' -p 1433:1433 -d microsoft/mssql-server-linux:2017-latest
-- sudo apt install libc6-dev
-- sudo apt install libgdiplus
+- sudo apt-get install -y --no-install-recommends libc6-dev libgdiplus dotnet-sdk-2.2 dotnet-sdk-3.1
+- sudo apt-get install -y --no-install-recommends mssql-tools mssql-server
+- sudo /opt/mssql/bin/mssql-conf -n setup accept-eula
script:
- dotnet publish "./Tools/rdmp" -r linux-x64
diff --git a/Application/ResearchDataManagementPlatform/WindowManagement/WindowFactory.cs b/Application/ResearchDataManagementPlatform/WindowManagement/WindowFactory.cs
index dce76fa658..f5849b6500 100644
--- a/Application/ResearchDataManagementPlatform/WindowManagement/WindowFactory.cs
+++ b/Application/ResearchDataManagementPlatform/WindowManagement/WindowFactory.cs
@@ -18,6 +18,7 @@
using Rdmp.UI.Icons;
using Rdmp.UI.ItemActivation;
using Rdmp.UI.Refreshing;
+using Rdmp.UI.SimpleControls;
using Rdmp.UI.SingleControlForms;
using Rdmp.UI.TestsAndSetup.ServicePropogation;
using ResearchDataManagementPlatform.WindowManagement.ContentWindowTracking.Persistence;
@@ -123,6 +124,9 @@ private void AddControlToDockContent(IActivateItems activator, Control control,D
if (control is IConsultableBeforeClosing consult)
content.FormClosing += consult.ConsultAboutClosing;
+ if(control is ISaveableUI saveable)
+ content.FormClosing += (s,e)=>saveable.GetObjectSaverButton()?.CheckForUnsavedChangesAnOfferToSave();
+
content.KeyPreview = true;
if (content is RDMPSingleControlTab tab)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc7d9558ab..1d90bc1052 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
...
+## [4.1.6] - 2020-08-04
+
+### Added
+
+- Added 'Save Changes' prompt when closing tabs
+- Added Import command for bringing in one or more [CohortIdentificationConfiguration] into an existing container (like Merge / UnMerge but for existing configurations)
+- Added checks for LoadProgress dates being in sensible ranges during DLE
+
+### Fixed
+
+- Fixed [bug when parsing lists of ints in CLI](https://github.com/HicServices/RDMP/issues/84)
+
## [4.1.5] - 2020-07-14
### Added
@@ -486,7 +498,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed Culture (e.g. en-us) not being passed correctly in DelimitedFlatFileAttacher
- Fixed bug where Updater would show older versions of RDMP as installable 'updates'
-[Unreleased]: https://github.com/HicServices/RDMP/compare/v4.1.5...develop
+[Unreleased]: https://github.com/HicServices/RDMP/compare/v4.1.6...develop
+[4.1.6]: https://github.com/HicServices/RDMP/compare/v4.1.5...v4.1.6
[4.1.5]: https://github.com/HicServices/RDMP/compare/v4.1.4...v4.1.5
[4.1.4]: https://github.com/HicServices/RDMP/compare/v4.1.3...v4.1.4
[4.1.3]: https://github.com/HicServices/RDMP/compare/v4.1.2...v4.1.3
@@ -535,3 +548,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[Pipeline]: ./Documentation/CodeTutorials/Glossary.md#Pipeline
[Lookup]: ./Documentation/CodeTutorials/Glossary.md#Lookup
+[CohortIdentificationConfiguration]: ./Documentation/CodeTutorials/Glossary.md#CohortIdentificationConfiguration
\ No newline at end of file
diff --git a/Documentation/CodeTutorials/Packages.md b/Documentation/CodeTutorials/Packages.md
index 1a143afea9..e04e98af28 100644
--- a/Documentation/CodeTutorials/Packages.md
+++ b/Documentation/CodeTutorials/Packages.md
@@ -20,7 +20,7 @@
| CsvHelper | [GitHub](https://github.com/JoshClose/CsvHelper) | [15.0.5](https://www.nuget.org/packages/CsvHelper/15.0.5) | MS-PL / Apache 2.0 | Enables reading/writing CSV files |
| NPOI | [GitHub](https://github.com/tonyqus/npoi) | [2.4.1](https://www.nuget.org/packages/NPOI/2.4.1) | Apache 2.0 | Enables reading/writing Microsoft Excel files |
| ExcelNumberFormat | [GitHub](https://github.com/andersnm/ExcelNumberFormat) | [1.0.10](https://www.nuget.org/packages/ExcelNumberFormat/1.0.10) |[MIT](https://opensource.org/licenses/MIT) | Handles translating number formats from Excel formats into usable values | |
-| [NLog](https://nlog-project.org/) | [GitHub](https://github.com/NLog/NLog) | [4.7.2](https://www.nuget.org/packages/NLog/4.7.2) | [BSD 3-Clause](https://github.com/NLog/NLog/blob/dev/LICENSE.txt) | Flexible user configurable logging | |
+| [NLog](https://nlog-project.org/) | [GitHub](https://github.com/NLog/NLog) | [4.7.3](https://www.nuget.org/packages/NLog/4.7.3) | [BSD 3-Clause](https://github.com/NLog/NLog/blob/dev/LICENSE.txt) | Flexible user configurable logging | |
| HIC.FAnsiSql |[GitHub](https://github.com/HicServices/FAnsiSql) | [1.0.2](https://www.nuget.org/packages/HIC.FansiSql/1.0.2) | [GPL 3.0](https://www.gnu.org/licenses/gpl-3.0.html) | [DBMS] abstraction layer |
| HIC.BadMedicine | [GitHub](https://github.com/HicServices/BadMedicine) | [0.1.6](https://www.nuget.org/packages/HIC.BadMedicine/0.1.6) | [GPL 3.0](https://www.gnu.org/licenses/gpl-3.0.html) | Generate Test Datasets for tests/exericses |
| SSH.NET | [GitHub](https://github.com/sshnet/SSH.NET) | [2016.1.0](https://www.nuget.org/packages/SSH.NET/2016.1.0) | [MIT](https://github.com/sshnet/SSH.NET/blob/develop/LICENSE) | Enables fetching files from SFTP servers |
diff --git a/Plugins/Plugin.Test/Plugin.Test.nuspec b/Plugins/Plugin.Test/Plugin.Test.nuspec
index 09094cfb9a..c9529fab4c 100644
--- a/Plugins/Plugin.Test/Plugin.Test.nuspec
+++ b/Plugins/Plugin.Test/Plugin.Test.nuspec
@@ -21,7 +21,7 @@
-
+
diff --git a/Plugins/Plugin.UI/Plugin.UI.nuspec b/Plugins/Plugin.UI/Plugin.UI.nuspec
index 9c1c4f9954..4e6c2fe0ce 100644
--- a/Plugins/Plugin.UI/Plugin.UI.nuspec
+++ b/Plugins/Plugin.UI/Plugin.UI.nuspec
@@ -24,7 +24,7 @@
-
+
diff --git a/Plugins/Plugin/Plugin.nuspec b/Plugins/Plugin/Plugin.nuspec
index 6901432fd7..52e9e1d093 100644
--- a/Plugins/Plugin/Plugin.nuspec
+++ b/Plugins/Plugin/Plugin.nuspec
@@ -18,7 +18,7 @@
-
+
diff --git a/Rdmp.Core.Tests/CohortCreation/CohortIdentificationConfigurationMergerTests.cs b/Rdmp.Core.Tests/CohortCreation/CohortIdentificationConfigurationMergerTests.cs
index eef8df6a4d..62a03e0e76 100644
--- a/Rdmp.Core.Tests/CohortCreation/CohortIdentificationConfigurationMergerTests.cs
+++ b/Rdmp.Core.Tests/CohortCreation/CohortIdentificationConfigurationMergerTests.cs
@@ -119,5 +119,44 @@ public void TestSimpleUnMerge()
Assert.IsFalse(results[1].RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Intersect(new []{ aggregate1,aggregate2,aggregate3}).Any(),"Expected new aggregates to be new!");
}
+
+ [Test]
+ public void TestSimpleImportCic()
+ {
+ var merger = new CohortIdentificationConfigurationMerger(CatalogueRepository);
+
+ var cic1 = new CohortIdentificationConfiguration(CatalogueRepository,"cic1");
+ var cic2 = new CohortIdentificationConfiguration(CatalogueRepository,"cic2");
+
+ cic1.CreateRootContainerIfNotExists();
+ var root1 = cic1.RootCohortAggregateContainer;
+ root1.Name = "Root1";
+ root1.SaveToDatabase();
+ root1.AddChild(aggregate1,1);
+
+ cic2.CreateRootContainerIfNotExists();
+ var root2 = cic2.RootCohortAggregateContainer;
+ root2.Name = "Root2";
+ root2.SaveToDatabase();
+ root2.AddChild(aggregate2,2);
+
+ Assert.AreEqual(1,cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count);
+ Assert.AreEqual(1,cic2.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count);
+
+ int numberOfCicsBefore = CatalogueRepository.GetAllObjects().Count();
+
+ //import 2 into 1
+ merger.Import(new []{cic2 },cic1.RootCohortAggregateContainer);
+
+ //no new cics
+ Assert.AreEqual(numberOfCicsBefore,CatalogueRepository.GetAllObjects().Count());
+
+ // cic 1 should now have both aggregates
+ Assert.AreEqual(2,cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count);
+
+ Assert.AreEqual("Root1",cic1.RootCohortAggregateContainer.Name);
+ Assert.AreEqual("Root2",cic1.RootCohortAggregateContainer.GetSubContainers()[0].Name);
+
+ }
}
}
diff --git a/Rdmp.Core.Tests/CommandExecution/CommandCliTests.cs b/Rdmp.Core.Tests/CommandExecution/CommandCliTests.cs
index 755bd5aae2..f6f97aa0eb 100644
--- a/Rdmp.Core.Tests/CommandExecution/CommandCliTests.cs
+++ b/Rdmp.Core.Tests/CommandExecution/CommandCliTests.cs
@@ -5,6 +5,8 @@
// 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 Moq;
using Rdmp.Core.CommandExecution;
using Rdmp.Core.CommandLine.Interactive;
using ReusableLibraryCode.Checks;
@@ -35,5 +37,14 @@ protected CommandInvoker GetInvoker()
return invoker;
}
+
+ protected Mock GetMockActivator()
+ {
+ var mock = new Mock();
+ mock.Setup(m => m.RepositoryLocator).Returns(RepositoryLocator);
+ mock.Setup(m => m.GetDelegates()).Returns(new List());
+ mock.Setup(m => m.Show(It.IsAny()));
+ return mock;
+ }
}
}
\ No newline at end of file
diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandListTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandListTests.cs
new file mode 100644
index 0000000000..fefbb0327c
--- /dev/null
+++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandListTests.cs
@@ -0,0 +1,62 @@
+// 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 Moq;
+using NUnit.Framework;
+using Rdmp.Core.CommandExecution.AtomicCommands;
+using Rdmp.Core.CommandLine.Interactive.Picking;
+using Rdmp.Core.Curation.Data;
+using System.Text.RegularExpressions;
+
+namespace Rdmp.Core.Tests.CommandExecution
+{
+ class TestsExecuteCommandList : CommandCliTests
+ {
+ [Test]
+ public void Test_ExecuteCommandList_NoCataloguesParsing()
+ {
+ foreach(var cat in RepositoryLocator.CatalogueRepository.GetAllObjects())
+ cat.DeleteInDatabase();
+
+ Assert.IsEmpty(RepositoryLocator.CatalogueRepository.GetAllObjects());
+
+ GetInvoker().ExecuteCommand(typeof(ExecuteCommandList),
+ new CommandLineObjectPicker(new string[]{ "Catalogue"}, RepositoryLocator));
+ }
+
+ [Test]
+ public void Test_ExecuteCommandList_OneCatalogueParsing()
+ {
+ var c = WhenIHaveA();
+
+ GetInvoker().ExecuteCommand(typeof(ExecuteCommandList),
+ new CommandLineObjectPicker(new string[]{ "Catalogue"}, RepositoryLocator));
+
+ c.DeleteInDatabase();
+ }
+ [Test]
+ public void Test_ExecuteCommandList_OneCatalogue()
+ {
+ var c = WhenIHaveA();
+ c.Name = "fff";
+ c.SaveToDatabase();
+
+ var mock = GetMockActivator();
+
+ var cmd = new ExecuteCommandList(mock.Object,new []{c});
+ Assert.IsFalse(cmd.IsImpossible,cmd.ReasonCommandImpossible);
+
+ cmd.Execute();
+
+ string contents = Regex.Escape($"{c.ID}:fff");
+
+ // Called once
+ mock.Verify(m => m.Show(It.IsRegex(contents)), Times.Once());
+
+ c.DeleteInDatabase();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandAssociateCatalogueWithLoadMetadata.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandAssociateCatalogueWithLoadMetadata.cs
new file mode 100644
index 0000000000..ec147f7b46
--- /dev/null
+++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandAssociateCatalogueWithLoadMetadata.cs
@@ -0,0 +1,42 @@
+// 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 NUnit.Framework;
+using Rdmp.Core.CommandExecution.AtomicCommands;
+using Rdmp.Core.CommandLine.Interactive.Picking;
+using Rdmp.Core.Curation.Data;
+using Rdmp.Core.Curation.Data.DataLoad;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Rdmp.Core.Tests.CommandExecution
+{
+ class TestExecuteCommandAssociateCatalogueWithLoadMetadata : CommandCliTests
+ {
+
+ [Test]
+ public void TestExecuteCommandAssociateCatalogueWithLoadMetadata_Simple()
+ {
+ var cata1 = new Catalogue(RepositoryLocator.CatalogueRepository,"fff");
+ var cata2 = new Catalogue(RepositoryLocator.CatalogueRepository,"bbb");
+
+ Assert.IsNull(cata1.LoadMetadata);
+ Assert.IsNull(cata2.LoadMetadata);
+
+ var lmd = new LoadMetadata(RepositoryLocator.CatalogueRepository,"mylmd");
+
+ GetInvoker().ExecuteCommand(typeof(ExecuteCommandAssociateCatalogueWithLoadMetadata),
+ new CommandLineObjectPicker(new[]{$"LoadMetadata:{lmd.ID}", "Catalogue:fff"}, RepositoryLocator));
+
+ cata1.RevertToDatabaseState();
+ cata2.RevertToDatabaseState();
+
+ Assert.AreEqual(lmd.ID,cata1.LoadMetadata_ID);
+ Assert.IsNull(cata2.LoadMetadata);
+ }
+ }
+}
diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribeCommand.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribeCommand.cs
index 500ebd8710..eeb94bf57f 100644
--- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribeCommand.cs
+++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribeCommand.cs
@@ -16,16 +16,8 @@
namespace Rdmp.Core.Tests.CommandExecution
{
- class TestExecuteCommandDescribeCommand : UnitTests
+ class TestExecuteCommandDescribeCommand : CommandCliTests
{
- private Mock GetMock()
- {
- var mock = new Mock();
- mock.Setup(m => m.RepositoryLocator).Returns(RepositoryLocator);
- mock.Setup(m => m.GetDelegates()).Returns(new List());
- mock.Setup(m => m.Show(It.IsAny()));
- return mock;
- }
///
/// Asserts that the help text matches your text
@@ -34,7 +26,7 @@ private Mock GetMock()
///
private void AssertHelpIs(string expectedHelp, Type forCommand)
{
- var mock = GetMock();
+ var mock = GetMockActivator();
var cmd = new ExecuteCommandDescribeCommand(mock.Object, forCommand);
Assert.IsFalse(cmd.IsImpossible,cmd.ReasonCommandImpossible);
diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSet.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSet.cs
index 9254bddba8..f3de5afc0f 100644
--- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSet.cs
+++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSet.cs
@@ -12,6 +12,7 @@
using Rdmp.Core.CommandExecution.AtomicCommands;
using Rdmp.Core.CommandLine.Interactive.Picking;
using Rdmp.Core.Curation.Data;
+using Rdmp.Core.Curation.Data.DataLoad;
using Tests.Common;
namespace Rdmp.Core.Tests.CommandExecution
@@ -43,5 +44,33 @@ public void Test_CatalogueDescription_Null()
Assert.IsNull(cata.Description);
}
+
+ [Test]
+ public void TestExecuteCommandSet_SetArrayValueFromCLI()
+ {
+ var pta = WhenIHaveA();
+ pta.SetType(typeof(TableInfo[]));
+ pta.Name = "TablesToIsolate";
+ pta.SaveToDatabase();
+
+ var t1 = WhenIHaveA();
+ var t2 = WhenIHaveA();
+ var t3 = WhenIHaveA();
+ var t4 = WhenIHaveA();
+
+ var ids = t1.ID + "," + t2.ID + "," + t3.ID + "," + t4.ID;
+
+ Assert.IsNull(pta.Value);
+ Assert.IsNull(pta.GetValueAsSystemType());
+
+ GetInvoker().ExecuteCommand(typeof(ExecuteCommandSet),new CommandLineObjectPicker(new []{"ProcessTaskArgument:TablesToIsolate" ,"Value",ids},RepositoryLocator));
+
+ Assert.AreEqual(ids,pta.Value);
+
+ Assert.Contains(t1,(TableInfo[])pta.GetValueAsSystemType());
+ Assert.Contains(t2,(TableInfo[])pta.GetValueAsSystemType());
+ Assert.Contains(t3,(TableInfo[])pta.GetValueAsSystemType());
+ Assert.Contains(t4,(TableInfo[])pta.GetValueAsSystemType());
+ }
}
}
diff --git a/Rdmp.Core.Tests/CommandLine/CommandLineObjectPickerTests.cs b/Rdmp.Core.Tests/CommandLine/CommandLineObjectPickerTests.cs
index 26bd55517e..f151ab8d03 100644
--- a/Rdmp.Core.Tests/CommandLine/CommandLineObjectPickerTests.cs
+++ b/Rdmp.Core.Tests/CommandLine/CommandLineObjectPickerTests.cs
@@ -120,6 +120,34 @@ public void Test_PickCatalogueByName_PickTwo()
Assert.AreEqual(2,picker[0].DatabaseEntities.Count);
}
+ [Test]
+ public void TestPicker_TypeYieldsEmptyArrayOfObjects()
+ {
+ foreach(var cat in RepositoryLocator.CatalogueRepository.GetAllObjects())
+ cat.DeleteInDatabase();
+
+ Assert.IsEmpty(RepositoryLocator.CatalogueRepository.GetAllObjects());
+
+ //when interpreting the string "Catalogue" for a command
+ var picker = new CommandLineObjectPicker(new []{"Catalogue" },RepositoryLocator);
+
+ //we can pick it as either a Catalogue or a collection of all the Catalogues
+ Assert.AreEqual(typeof(Catalogue),picker.Arguments.Single().Type);
+ Assert.IsEmpty(picker.Arguments.Single().DatabaseEntities);
+
+ //when interpretting as a Type we get Catalogue
+ Assert.IsTrue(picker.Arguments.First().HasValueOfType(typeof(Type)));
+ Assert.AreEqual(typeof(Catalogue),picker.Arguments.Single().GetValueForParameterOfType(typeof(Type)));
+
+ //if it is looking for an ienumerable of objects
+ Assert.IsTrue(picker.Arguments.First().HasValueOfType(typeof(IMapsDirectlyToDatabaseTable[])));
+ Assert.IsEmpty((IMapsDirectlyToDatabaseTable[])picker.Arguments.First().GetValueForParameterOfType(typeof(IMapsDirectlyToDatabaseTable[])));
+
+ Assert.IsTrue(picker.Arguments.First().HasValueOfType(typeof(Catalogue[])));
+ Assert.IsEmpty(((Catalogue[])picker.Arguments.First().GetValueForParameterOfType(typeof(Catalogue[]))).ToArray());
+
+ }
+
[TestCase(typeof(PickDatabase))]
[TestCase(typeof(PickTable))]
[TestCase(typeof(PickObjectByID))]
diff --git a/Rdmp.Core.Tests/Curation/Integration/LoadProgressUnitTests.cs b/Rdmp.Core.Tests/Curation/Integration/LoadProgressUnitTests.cs
new file mode 100644
index 0000000000..028777f895
--- /dev/null
+++ b/Rdmp.Core.Tests/Curation/Integration/LoadProgressUnitTests.cs
@@ -0,0 +1,105 @@
+// 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 NUnit.Framework;
+using Rdmp.Core.Curation;
+using Rdmp.Core.Curation.Data;
+using Rdmp.Core.DataLoad.Engine.Job.Scheduling;
+using Rdmp.Core.DataLoad.Engine.LoadProcess.Scheduling.Strategy;
+using ReusableLibraryCode.Checks;
+using ReusableLibraryCode.Progress;
+using System;
+using System.IO;
+using Tests.Common;
+
+namespace Rdmp.Core.Tests.Curation.Integration
+{
+ public class LoadProgressUnitTests : UnitTests
+ {
+ [Test]
+ public void LoadProgress_Checks_BadDates()
+ {
+ var lp = WhenIHaveA();
+
+ lp.Check(new ThrowImmediatelyCheckNotifier());
+
+ //Bad Origin Date
+ lp.OriginDate = DateTime.Now.AddDays(1);
+ Assert.Throws(()=>lp.Check(new ThrowImmediatelyCheckNotifier()));
+
+ //Back to normal
+ lp.RevertToDatabaseState();
+ lp.Check(new ThrowImmediatelyCheckNotifier());
+
+ //Bad ProgressDate
+ lp.DataLoadProgress = DateTime.Now.AddDays(1);
+ Assert.Throws(()=>lp.Check(new ThrowImmediatelyCheckNotifier()));
+
+ //Back to normal
+ lp.RevertToDatabaseState();
+ lp.Check(new ThrowImmediatelyCheckNotifier());
+
+
+ //negative progress
+ lp.OriginDate = new DateTime(2001,1,1);
+ lp.DataLoadProgress = new DateTime(2000,1,1);
+ Assert.Throws(()=>lp.Check(new ThrowImmediatelyCheckNotifier()));
+
+ // valid progress (1 year)
+ lp.OriginDate = new DateTime(2001,1,1);
+ lp.DataLoadProgress = new DateTime(2002,1,1);
+ lp.Check(new ThrowImmediatelyCheckNotifier());
+ }
+
+ [Test]
+ public void LoadProgress_JobFactory_NoDates()
+ {
+ var lp = WhenIHaveA();
+
+
+
+ lp.OriginDate = new DateTime(2001,1,1);
+
+ // We are fully up-to-date
+ lp.DataLoadProgress = DateTime.Now;
+
+ lp.Check(new ThrowImmediatelyCheckNotifier());
+
+ var stratFactory = new JobDateGenerationStrategyFactory(new AnyAvailableLoadProgressSelectionStrategy(lp.LoadMetadata));
+ var strat = stratFactory.Create(lp,new ThrowImmediatelyDataLoadEventListener());
+
+ var dir = LoadDirectory.CreateDirectoryStructure(new DirectoryInfo(TestContext.CurrentContext.WorkDirectory),"LoadProgress_JobFactory_NoDates",true);
+
+ var lmd = lp.LoadMetadata;
+ lmd.LocationOfFlatFiles = dir.RootPath.FullName;
+
+ foreach(var cata in lmd.GetAllCatalogues())
+ {
+ cata.LoggingDataTask = "ff";
+ cata.SaveToDatabase();
+ }
+
+
+ lmd.SaveToDatabase();
+
+
+ var jobFactory = new SingleScheduledJobFactory(lp,strat,999,lp.LoadMetadata,null);
+ var ex = Assert.Throws(()=>jobFactory.Create(RepositoryLocator,new ThrowImmediatelyDataLoadEventListener(),null));
+
+ Assert.AreEqual("DatesToRetrieve was empty for load 'MyLoad'. Possibly the load is already up to date?",ex.Message);
+
+ // We have 1 day to load (date is the last fully loaded date)
+ lp.DataLoadProgress = DateTime.Now.AddDays(-2);
+ lp.SaveToDatabase();
+
+ strat = stratFactory.Create(lp,new ThrowImmediatelyDataLoadEventListener());
+ jobFactory = new SingleScheduledJobFactory(lp,strat,999,lp.LoadMetadata,null);
+
+ var job = jobFactory.Create(RepositoryLocator,new ThrowImmediatelyDataLoadEventListener(),null);
+ Assert.AreEqual(1,((ScheduledDataLoadJob)job).DatesToRetrieve.Count);
+ }
+ }
+}
diff --git a/Rdmp.Core.Tests/Curation/Integration/PipelineTests.cs b/Rdmp.Core.Tests/Curation/Integration/PipelineTests.cs
index 9c11ad784c..40a000e204 100644
--- a/Rdmp.Core.Tests/Curation/Integration/PipelineTests.cs
+++ b/Rdmp.Core.Tests/Curation/Integration/PipelineTests.cs
@@ -159,5 +159,36 @@ public void CloneAPipeline(bool revertAfterClone)
p.DeleteInDatabase();
p2.DeleteInDatabase();
}
+
+ [Test]
+ public void CloneAPipeline_BrokenPipes()
+ {
+ Pipeline p = new Pipeline(CatalogueRepository);
+
+ //Setup a pipeline with a source component type that doesn't exist
+ var source = new PipelineComponent(CatalogueRepository, p, typeof (DelimitedFlatFileAttacher), 0);
+ source.Class = "Trollololol";
+
+ var arg = source.CreateNewArgument();
+
+ //Also give the source component a non existent argument
+ arg.GetType().GetProperty("Type").SetValue(arg,"fffffzololz");
+ arg.SaveToDatabase();
+
+ p.SourcePipelineComponent_ID = source.ID;
+ p.SaveToDatabase();
+
+ Assert.AreEqual("fffffzololz",p.Source.GetAllArguments().Single().Type);
+
+ var clone = p.Clone();
+
+ Assert.AreEqual(clone.Source.Class,p.Source.Class);
+ Assert.AreEqual("fffffzololz",clone.Source.GetAllArguments().Single().Type);
+
+ p.DeleteInDatabase();
+ clone.DeleteInDatabase();
+
+
+ }
}
}
diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandAssociateCatalogueWithLoadMetadata.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandAssociateCatalogueWithLoadMetadata.cs
index 23f7f99c39..e0a40fb3ed 100644
--- a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandAssociateCatalogueWithLoadMetadata.cs
+++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandAssociateCatalogueWithLoadMetadata.cs
@@ -9,6 +9,7 @@
using Rdmp.Core.Curation.Data;
using Rdmp.Core.Curation.Data.DataLoad;
using Rdmp.Core.Icons.IconProvision;
+using Rdmp.Core.Repositories.Construction;
using ReusableLibraryCode.Icons.IconProvision;
namespace Rdmp.Core.CommandExecution.AtomicCommands
@@ -19,7 +20,22 @@ public class ExecuteCommandAssociateCatalogueWithLoadMetadata:BasicCommandExecut
private readonly Catalogue[] _availableCatalogues;
private readonly ICatalogue[] _otherCatalogues;
private Catalogue[] _chosenCatalogues;
+
+ [UseWithObjectConstructor]
+ public ExecuteCommandAssociateCatalogueWithLoadMetadata(IBasicActivateItems activator, LoadMetadata loadMetadata, Catalogue[] toAssociate) : this(activator,loadMetadata)
+ {
+ //if command is possible, select those that are available for association
+ if(!IsImpossible)
+ {
+ _chosenCatalogues = _availableCatalogues.Intersect(toAssociate).ToArray();
+
+ if(_chosenCatalogues.Length == 0)
+ SetImpossible($"None of the provided Catalogues are available for association with the LoadMetadata '{loadMetadata}'");
+ }
+
+
+ }
public ExecuteCommandAssociateCatalogueWithLoadMetadata(IBasicActivateItems activator, LoadMetadata loadMetadata) : base(activator)
{
_loadMetadata = loadMetadata;
diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandImportCohortIdentificationConfiguration.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandImportCohortIdentificationConfiguration.cs
new file mode 100644
index 0000000000..f53b3abffd
--- /dev/null
+++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandImportCohortIdentificationConfiguration.cs
@@ -0,0 +1,64 @@
+// 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 Rdmp.Core.Curation.Data.Cohort;
+using Rdmp.Core.Icons.IconProvision;
+using Rdmp.Core.Repositories;
+using ReusableLibraryCode.Icons.IconProvision;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+
+namespace Rdmp.Core.CommandExecution.AtomicCommands
+{
+ ///
+ /// Clone and import one or more into a root or subcontainer of another
+ ///
+ public class ExecuteCommandImportCohortIdentificationConfiguration : BasicCommandExecution
+ {
+ public CohortAggregateContainer IntoContainer { get; }
+ public CohortIdentificationConfiguration[] ToImport{get;}
+
+ public ExecuteCommandImportCohortIdentificationConfiguration(IBasicActivateItems activator,CohortIdentificationConfiguration[] toImport, CohortAggregateContainer intoContainer) : base(activator)
+ {
+ ToImport = toImport;
+ IntoContainer = intoContainer;
+
+ if(IntoContainer == null)
+ {
+ SetImpossible("You must specify a container");
+ return;
+ }
+
+ }
+ public override Image GetImage(IIconProvider iconProvider)
+ {
+ return iconProvider.GetImage(RDMPConcept.CohortIdentificationConfiguration,OverlayKind.Add);
+ }
+ public override void Execute()
+ {
+ base.Execute();
+
+ var import = ToImport;
+
+ if(import == null)
+ if(!SelectMany(BasicActivator.RepositoryLocator.CatalogueRepository.GetAllObjects(),out import))
+ return;
+
+ if(import == null || !import.Any())
+ return;
+
+
+ var merger = new CohortIdentificationConfigurationMerger((CatalogueRepository)BasicActivator.RepositoryLocator.CatalogueRepository);
+ merger.Import(import,IntoContainer);
+
+ Publish(IntoContainer);
+ }
+
+ }
+}
diff --git a/Rdmp.Core/CommandLine/Interactive/Picking/CommandLineObjectPickerArgumentValue.cs b/Rdmp.Core/CommandLine/Interactive/Picking/CommandLineObjectPickerArgumentValue.cs
index 4b3f6cb354..58b9ce9c82 100644
--- a/Rdmp.Core/CommandLine/Interactive/Picking/CommandLineObjectPickerArgumentValue.cs
+++ b/Rdmp.Core/CommandLine/Interactive/Picking/CommandLineObjectPickerArgumentValue.cs
@@ -226,16 +226,18 @@ public CommandLineObjectPickerArgumentValue Merge(IEnumerable
+ /// Clone and import one or more into the target
+ ///
+ ///
+ /// The container into which you want to add the
+ public void Import(CohortIdentificationConfiguration[] cics, CohortAggregateContainer into)
+ {
+ var cicInto = into.GetCohortIdentificationConfiguration();
+
+ if(cicInto == null)
+ throw new ArgumentException($"Cannot import into orphan container '{into}'",nameof(into));
+
+ //clone them
+ var cicClones = new CohortIdentificationConfiguration[cics.Length];
+ try
+ {
+ for (int i = 0; i < cics.Length; i++)
+ {
+ cicClones[i] = cics[i].CreateClone(new ThrowImmediatelyCheckNotifier());
+ }
+ }
+ catch(Exception ex)
+ {
+ throw new Exception("Error during pre import cloning stage, no import will be attempted",ex);
+ }
+
+
+ using(_repository.BeginNewTransactedConnection())
+ {
+ //Grab the root container of each of the input cics
+ foreach(CohortIdentificationConfiguration cic in cicClones)
+ {
+ var container = cic.RootCohortAggregateContainer;
+
+ //clear them to avoid dual parentage
+ cic.RootCohortAggregateContainer_ID = null;
+ cic.SaveToDatabase();
+
+ //add them into the target SET operation container you are importing into
+ into.AddChild(container);
+
+ // Make the new name of all the AggregateConfigurations match the owner of import into container
+ foreach(var child in container.GetAllAggregateConfigurationsRecursively())
+ EnsureNamingConvention(cicInto,child);
+
+ // Delete the old now empty clones
+ cic.DeleteInDatabase();
+ }
+
+ //finish transaction
+ _repository.EndTransactedConnection(true);
+ }
+ }
+
+
+
private void EnsureNamingConvention(CohortIdentificationConfiguration cic, AggregateConfiguration ac)
{
//clear any old cic_x prefixes
diff --git a/Rdmp.Core/Curation/Data/ILoadProgress.cs b/Rdmp.Core/Curation/Data/ILoadProgress.cs
index 58f6766a6e..64a414acf1 100644
--- a/Rdmp.Core/Curation/Data/ILoadProgress.cs
+++ b/Rdmp.Core/Curation/Data/ILoadProgress.cs
@@ -8,6 +8,7 @@
using MapsDirectlyToDatabaseTable;
using Rdmp.Core.Curation.Data.Cache;
using Rdmp.Core.Curation.Data.DataLoad;
+using ReusableLibraryCode.Checks;
namespace Rdmp.Core.Curation.Data
{
@@ -15,7 +16,7 @@ namespace Rdmp.Core.Curation.Data
/// Describes the progress of a large iterative load which cannot be completed in a single batch. Includes start and end dates for what is trying to
/// be loaded as well as how far through that process progress has been made up to date.
///
- public interface ILoadProgress :INamed
+ public interface ILoadProgress :INamed, ICheckable
{
///
/// The date the dataset starts at, this is in dataset time e.g. if you have prescribing records held from 2001-01-01 to present then the is 2001-01-01
diff --git a/Rdmp.Core/Curation/Data/LoadProgress.cs b/Rdmp.Core/Curation/Data/LoadProgress.cs
index 0366e3a312..cb683e4450 100644
--- a/Rdmp.Core/Curation/Data/LoadProgress.cs
+++ b/Rdmp.Core/Curation/Data/LoadProgress.cs
@@ -14,11 +14,12 @@
using Rdmp.Core.Curation.Data.DataLoad;
using Rdmp.Core.Repositories;
using ReusableLibraryCode.Annotations;
+using ReusableLibraryCode.Checks;
namespace Rdmp.Core.Curation.Data
{
///
- public class LoadProgress : DatabaseEntity, ILoadProgress
+ public class LoadProgress : DatabaseEntity, ILoadProgress, ICheckable
{
#region Database Properties
private bool _isDisabled;
@@ -124,5 +125,19 @@ public override string ToString()
{
return Name + " ID=" + ID;
}
+
+ public void Check(ICheckNotifier notifier)
+ {
+ if(OriginDate != null && DataLoadProgress != null)
+ if(OriginDate > DataLoadProgress)
+ notifier.OnCheckPerformed(new CheckEventArgs($"OriginDate of '{Name}' is set after DataLoadProgress date. LoadProgress cannot have negative progress",CheckResult.Fail));
+
+ if(OriginDate != null && OriginDate > DateTime.Now)
+ notifier.OnCheckPerformed(new CheckEventArgs($"OriginDate cannot be in the future ({Name})",CheckResult.Fail));
+
+ if(DataLoadProgress != null && DataLoadProgress > DateTime.Now)
+ notifier.OnCheckPerformed(new CheckEventArgs($"DataLoadProgress cannot be in the future ({Name})",CheckResult.Fail));
+
+ }
}
}
diff --git a/Rdmp.Core/Curation/Data/Pipelines/IPipelineComponentArgument.cs b/Rdmp.Core/Curation/Data/Pipelines/IPipelineComponentArgument.cs
index 1ae2fda4bf..7fa4de1389 100644
--- a/Rdmp.Core/Curation/Data/Pipelines/IPipelineComponentArgument.cs
+++ b/Rdmp.Core/Curation/Data/Pipelines/IPipelineComponentArgument.cs
@@ -20,5 +20,11 @@ public interface IPipelineComponentArgument : IArgument, IMapsDirectlyToDatabase
/// per public property with on the .
///
int PipelineComponent_ID { get; set; }
+
+ ///
+ /// Creates a new copy of the current argument and associates it with
+ ///
+ ///
+ void Clone(PipelineComponent intoTargetComponent);
}
}
\ No newline at end of file
diff --git a/Rdmp.Core/Curation/Data/Pipelines/PipelineComponent.cs b/Rdmp.Core/Curation/Data/Pipelines/PipelineComponent.cs
index a9316c6f4b..ac973fe641 100644
--- a/Rdmp.Core/Curation/Data/Pipelines/PipelineComponent.cs
+++ b/Rdmp.Core/Curation/Data/Pipelines/PipelineComponent.cs
@@ -142,15 +142,9 @@ public PipelineComponent Clone(Pipeline intoTargetPipeline)
var cataRepo = (ICatalogueRepository) intoTargetPipeline.Repository;
var clone = new PipelineComponent(cataRepo, intoTargetPipeline, GetClassAsSystemType(), Order);
- foreach (IPipelineComponentArgument argument in PipelineComponentArguments)
+ foreach (var argument in PipelineComponentArguments)
{
- var cloneArg = new PipelineComponentArgument(cataRepo, clone);
-
- cloneArg.Name = argument.Name;
- cloneArg.Value = argument.Value;
- cloneArg.SetType(argument.GetSystemType());
- cloneArg.Description = argument.Description;
- cloneArg.SaveToDatabase();
+ argument.Clone(clone);
}
clone.Name = Name;
diff --git a/Rdmp.Core/Curation/Data/Pipelines/PipelineComponentArgument.cs b/Rdmp.Core/Curation/Data/Pipelines/PipelineComponentArgument.cs
index 14da761d2d..44562b2c98 100644
--- a/Rdmp.Core/Curation/Data/Pipelines/PipelineComponentArgument.cs
+++ b/Rdmp.Core/Curation/Data/Pipelines/PipelineComponentArgument.cs
@@ -87,5 +87,17 @@ public IHasDependencies[] GetObjectsDependingOnThis()
{
return new IHasDependencies[0];
}
+
+ ///
+ public void Clone(PipelineComponent intoTargetComponent)
+ {
+ var cloneArg = new PipelineComponentArgument(intoTargetComponent.CatalogueRepository, intoTargetComponent);
+
+ cloneArg.Name = Name;
+ cloneArg.Value = Value;
+ cloneArg.Type = Type;
+ cloneArg.Description = Description;
+ cloneArg.SaveToDatabase();
+ }
}
}
diff --git a/Rdmp.Core/DataLoad/Engine/Checks/CheckEntireDataLoadProcess.cs b/Rdmp.Core/DataLoad/Engine/Checks/CheckEntireDataLoadProcess.cs
index 22b395a71d..a023ddb48d 100644
--- a/Rdmp.Core/DataLoad/Engine/Checks/CheckEntireDataLoadProcess.cs
+++ b/Rdmp.Core/DataLoad/Engine/Checks/CheckEntireDataLoadProcess.cs
@@ -47,6 +47,8 @@ public void Check(ICheckNotifier notifier)
//If the load is a progressable (loaded over time) then make sure any associated caches are compatible with the load ProcessTasks
foreach (ILoadProgress loadProgress in LoadMetadata.LoadProgresses)
{
+ loadProgress.Check(notifier);
+
var cp = loadProgress.CacheProgress;
if(cp != null)
{
diff --git a/Rdmp.Core/DataLoad/Engine/Job/Scheduling/MultipleScheduleJobFactory.cs b/Rdmp.Core/DataLoad/Engine/Job/Scheduling/MultipleScheduleJobFactory.cs
index 5b80fb6565..06b03058c0 100644
--- a/Rdmp.Core/DataLoad/Engine/Job/Scheduling/MultipleScheduleJobFactory.cs
+++ b/Rdmp.Core/DataLoad/Engine/Job/Scheduling/MultipleScheduleJobFactory.cs
@@ -47,7 +47,7 @@ public override bool HasJobs()
return _scheduleList.Any(loadProgress => _availableSchedules[loadProgress].GetTotalNumberOfJobs(OverrideNumberOfDaysToLoad??loadProgress.DefaultNumberOfDaysToLoadEachTime, false) > 0);
}
- public override IDataLoadJob Create(IRDMPPlatformRepositoryServiceLocator repositoryLocator,IDataLoadEventListener listener,HICDatabaseConfiguration configuration)
+ protected override ScheduledDataLoadJob CreateImpl(IRDMPPlatformRepositoryServiceLocator repositoryLocator,IDataLoadEventListener listener,HICDatabaseConfiguration configuration)
{
ScheduledDataLoadJob job;
var loadProgress = _scheduleList[_lastScheduleId];
diff --git a/Rdmp.Core/DataLoad/Engine/Job/Scheduling/ScheduledJobFactory.cs b/Rdmp.Core/DataLoad/Engine/Job/Scheduling/ScheduledJobFactory.cs
index ae2c4bb1bd..4aa6aab464 100644
--- a/Rdmp.Core/DataLoad/Engine/Job/Scheduling/ScheduledJobFactory.cs
+++ b/Rdmp.Core/DataLoad/Engine/Job/Scheduling/ScheduledJobFactory.cs
@@ -9,6 +9,8 @@
using Rdmp.Core.Logging;
using Rdmp.Core.Repositories;
using ReusableLibraryCode.Progress;
+using System;
+using System.Linq;
namespace Rdmp.Core.DataLoad.Engine.Job.Scheduling
{
@@ -27,7 +29,20 @@ protected ScheduledJobFactory(int? overrideNumberOfDaysToLoad, ILoadMetadata loa
LogManager = logManager;
}
- public abstract IDataLoadJob Create(IRDMPPlatformRepositoryServiceLocator repositoryLocator, IDataLoadEventListener listener,HICDatabaseConfiguration configuration);
+
public abstract bool HasJobs();
+
+
+ public IDataLoadJob Create(IRDMPPlatformRepositoryServiceLocator repositoryLocator, IDataLoadEventListener listener,HICDatabaseConfiguration configuration)
+ {
+ var job = CreateImpl(repositoryLocator,listener,configuration);
+
+ if(job.DatesToRetrieve == null || !job.DatesToRetrieve.Any())
+ throw new Exception($"DatesToRetrieve was empty for load '{LoadMetadata}'. Possibly the load is already up to date?");
+
+ return job;
+ }
+
+ protected abstract ScheduledDataLoadJob CreateImpl(IRDMPPlatformRepositoryServiceLocator repositoryLocator, IDataLoadEventListener listener, HICDatabaseConfiguration configuration);
}
}
\ No newline at end of file
diff --git a/Rdmp.Core/DataLoad/Engine/Job/Scheduling/SingleScheduledJobFactory.cs b/Rdmp.Core/DataLoad/Engine/Job/Scheduling/SingleScheduledJobFactory.cs
index de0f3c8d3d..24a3c48782 100644
--- a/Rdmp.Core/DataLoad/Engine/Job/Scheduling/SingleScheduledJobFactory.cs
+++ b/Rdmp.Core/DataLoad/Engine/Job/Scheduling/SingleScheduledJobFactory.cs
@@ -11,6 +11,8 @@
using Rdmp.Core.Logging;
using Rdmp.Core.Repositories;
using ReusableLibraryCode.Progress;
+using System;
+using System.Linq;
namespace Rdmp.Core.DataLoad.Engine.Job.Scheduling
{
@@ -34,7 +36,7 @@ public override bool HasJobs()
return _jobDateGenerationStrategy.GetTotalNumberOfJobs(OverrideNumberOfDaysToLoad??_loadProgress.DefaultNumberOfDaysToLoadEachTime, false) > 0;
}
- public override IDataLoadJob Create(IRDMPPlatformRepositoryServiceLocator repositoryLocator,IDataLoadEventListener listener,HICDatabaseConfiguration configuration)
+ protected override ScheduledDataLoadJob CreateImpl(IRDMPPlatformRepositoryServiceLocator repositoryLocator,IDataLoadEventListener listener,HICDatabaseConfiguration configuration)
{
var LoadDirectory = new LoadDirectory(LoadMetadata.LocationOfFlatFiles);
return new ScheduledDataLoadJob(repositoryLocator,JobDescription, LogManager, LoadMetadata, LoadDirectory, listener,configuration)
diff --git a/Rdmp.UI/ExtractionUIs/FilterUIs/ExtractionFilterUI.cs b/Rdmp.UI/ExtractionUIs/FilterUIs/ExtractionFilterUI.cs
index 4a551a0dac..777fc3c7fa 100644
--- a/Rdmp.UI/ExtractionUIs/FilterUIs/ExtractionFilterUI.cs
+++ b/Rdmp.UI/ExtractionUIs/FilterUIs/ExtractionFilterUI.cs
@@ -110,33 +110,6 @@ private void FigureOutGlobalsAndAutoComplete()
_autoCompleteProvider.RegisterForEvents(QueryEditor);
}
-
- ///
- /// Gives the user an option to save the changes to the filter (if they have unsaved changes) call things for example when closing the host form.
- ///
- public override void ConsultAboutClosing(object sender, FormClosingEventArgs e)
- {
- if (_extractionFilter != null && _extractionFilter.HasLocalChanges().Evaluation == ChangeDescription.DatabaseCopyDifferent)
- if (Activator.YesNo(
- "You have unsaved changes to Filter \"" + _extractionFilter.Name +
- "\", would you like to save these now?", "Save Changes to Filter?"))
- ObjectSaverButton1.Save();
- else
- {
- try
- {
- //So there are local changes to the filter but the user doesnt want to save them. We need to undo the local changes to the
- //object that we have a reference to. This is important because other classes might still have references to that object too
- //so we fetch a fresh copy out of the database (RevertChanges) and set each of the properties to the original (last saved) values
- _extractionFilter.RevertToDatabaseState();
- }
- catch (Exception ex)
- {
- ExceptionViewer.Show("Failed to revert changes on filter, did you delete it?",ex);
- }
- }
- }
-
private bool BeforeSave(DatabaseEntity databaseEntity)
{
SubstituteQueryEditorTextIfContainsLineComments();
diff --git a/Rdmp.UI/Menus/CohortAggregateContainerMenu.cs b/Rdmp.UI/Menus/CohortAggregateContainerMenu.cs
index 813625f8e7..4cd5da9aff 100644
--- a/Rdmp.UI/Menus/CohortAggregateContainerMenu.cs
+++ b/Rdmp.UI/Menus/CohortAggregateContainerMenu.cs
@@ -48,7 +48,8 @@ public CohortAggregateContainerMenu(RDMPContextMenuStripArgs args, CohortAggrega
Items.Add("Add Aggregate(s) into container", _activator.CoreIconProvider.GetImage(RDMPConcept.AggregateGraph, OverlayKind.Import), (s, e) => AddAggregates());
Items.Add("Import (Copy of) Cohort Set into container", _activator.CoreIconProvider.GetImage(RDMPConcept.CohortAggregate, OverlayKind.Import), (s, e) => AddCohortAggregate());
-
+ Add(new ExecuteCommandImportCohortIdentificationConfiguration(_activator,null,container));
+
foreach (ToolStripMenuItem item in Items)
item.Enabled = item.Enabled && (cic != null && !cic.Frozen);
diff --git a/Rdmp.UI/SimpleControls/ObjectSaverButton.cs b/Rdmp.UI/SimpleControls/ObjectSaverButton.cs
index 7248a8ded5..10b47fb64d 100644
--- a/Rdmp.UI/SimpleControls/ObjectSaverButton.cs
+++ b/Rdmp.UI/SimpleControls/ObjectSaverButton.cs
@@ -242,7 +242,8 @@ private bool IsDifferent()
public void CheckForUnsavedChangesAnOfferToSave()
{
- if (_o == null)
+ // If there is no object or it does not exist don't try to save it
+ if (_o == null || !_o.Exists())
return;
if (_isEnabled)
diff --git a/Reusable/MapsDirectlyToDatabaseTable/MapsDirectlyToDatabaseTable.csproj b/Reusable/MapsDirectlyToDatabaseTable/MapsDirectlyToDatabaseTable.csproj
index 9ce8ca5145..86a0d63329 100644
--- a/Reusable/MapsDirectlyToDatabaseTable/MapsDirectlyToDatabaseTable.csproj
+++ b/Reusable/MapsDirectlyToDatabaseTable/MapsDirectlyToDatabaseTable.csproj
@@ -23,7 +23,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs
index 46a3c9d80e..fcb5bb420f 100644
--- a/SharedAssemblyInfo.cs
+++ b/SharedAssemblyInfo.cs
@@ -6,7 +6,6 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// These should be replaced with correct values by the release process
-[assembly: AssemblyVersion("4.1.5")]
-[assembly: AssemblyFileVersion("4.1.5")]
-[assembly: AssemblyInformationalVersion("4.1.5")]
+[assembly: AssemblyVersion("4.1.6")]
+[assembly: AssemblyFileVersion("4.1.6")]
+[assembly: AssemblyInformationalVersion("4.1.6")]
diff --git a/appveyor.yml b/appveyor.yml
index 0fb4d0f58d..5a55ce9b4e 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -7,7 +7,13 @@ services:
- mysql
- postgresql101
+cache:
+ - '%USERPROFILE%\.nuget\packages -> **\*.csproj'
+ - C:\ProgramData\chocolatey\bin -> appveyor.yml
+ - C:\ProgramData\chocolatey\lib -> appveyor.yml
+
before_build:
+- cmd: if defined APPVEYOR_PULL_REQUEST_NUMBER appveyor exit
- dotnet restore --packages ./packages
- choco install opencover.portable