diff --git a/CHANGELOG.md b/CHANGELOG.md
index 172ecdb1dd..3bd8a30350 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
+
# Changelog
All notable changes to this project will be documented in this file.
@@ -7,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [8.4.0] - Unreleased
+- Add Ordering to Filters
+
## [8.3.1] - Unreleased
- Improve Performance of regenerating problems with child providers
diff --git a/Rdmp.Core/Curation/Data/Aggregation/AggregateFilter.cs b/Rdmp.Core/Curation/Data/Aggregation/AggregateFilter.cs
index 7b23404346..307a7ef8aa 100644
--- a/Rdmp.Core/Curation/Data/Aggregation/AggregateFilter.cs
+++ b/Rdmp.Core/Curation/Data/Aggregation/AggregateFilter.cs
@@ -1,4 +1,4 @@
-// Copyright (c) The University of Dundee 2018-2019
+// Copyright (c) The University of Dundee 2018-2024
// 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.
@@ -35,6 +35,7 @@ public class AggregateFilter : ConcreteFilter, IDisableable
private int? _clonedFromExtractionFilterID;
private int? _associatedColumnInfoID;
private bool _isDisabled;
+ private int _order;
///
public override int? ClonedFromExtractionFilter_ID
@@ -90,6 +91,8 @@ public IEnumerable AggregateFilterParameters
? Repository.GetObjectByID(FilterContainer_ID.Value)
: null;
+ public override int Order { get => _order; set => SetField(ref _order, value); }
+
#endregion
public AggregateFilter()
@@ -121,6 +124,7 @@ internal AggregateFilter(ICatalogueRepository repository, DbDataReader r) : base
Name = r["Name"] as string;
IsMandatory = (bool)r["IsMandatory"];
ClonedFromExtractionFilter_ID = ObjectToNullableInt(r["ClonedFromExtractionFilter_ID"]);
+ Order = int.Parse(r["Order"].ToString());
var associatedColumnInfo_ID = r["AssociatedColumnInfo_ID"];
if (associatedColumnInfo_ID != DBNull.Value)
diff --git a/Rdmp.Core/Curation/Data/ConcreteFilter.cs b/Rdmp.Core/Curation/Data/ConcreteFilter.cs
index c29ebbdeca..b8fe1f49de 100644
--- a/Rdmp.Core/Curation/Data/ConcreteFilter.cs
+++ b/Rdmp.Core/Curation/Data/ConcreteFilter.cs
@@ -1,4 +1,4 @@
-// Copyright (c) The University of Dundee 2018-2019
+// Copyright (c) The University of Dundee 2018-2024
// 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.
@@ -25,7 +25,7 @@ namespace Rdmp.Core.Curation.Data;
/// ConcreteFilter is used to provide UI editing of an IFilter without having to add persistence / DatabaseEntity logic to IFilter (which would break
/// SpontaneouslyInventedFilters)
///
-public abstract class ConcreteFilter : DatabaseEntity, IFilter, ICheckable
+public abstract class ConcreteFilter : DatabaseEntity, IFilter, ICheckable, IOrderable
{
///
protected ConcreteFilter(IRepository repository, DbDataReader r) : base(repository, r)
@@ -100,6 +100,7 @@ public bool IsMandatory
///
[NoMappingToDatabase]
public abstract IContainer FilterContainer { get; }
+ public abstract int Order { get; set; }
#endregion
diff --git a/Rdmp.Core/Curation/Data/ExtractionFilter.cs b/Rdmp.Core/Curation/Data/ExtractionFilter.cs
index f6ce6f8d4c..febd12b629 100644
--- a/Rdmp.Core/Curation/Data/ExtractionFilter.cs
+++ b/Rdmp.Core/Curation/Data/ExtractionFilter.cs
@@ -1,4 +1,4 @@
-// Copyright (c) The University of Dundee 2018-2019
+// Copyright (c) The University of Dundee 2018-2024
// 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.
@@ -40,6 +40,7 @@ public class ExtractionFilter : ConcreteFilter, IHasDependencies, IInjectKnown _knownExtractionFilterParameterSets;
+ private int _order;
///
/// The column in the which is best/most associated with this filter. A filter can query any column in any of the table(s) under
@@ -133,6 +134,8 @@ internal ExtractionFilter(ICatalogueRepository repository, DbDataReader r)
Description = r["Description"] as string;
Name = r["Name"] as string;
IsMandatory = (bool)r["IsMandatory"];
+ Order = int.Parse(r["Order"].ToString());
+
ClearAllInjections();
}
@@ -154,6 +157,7 @@ public override int? ClonedFromExtractionFilter_ID
set => throw new NotSupportedException(
"ClonedFromExtractionFilter_ID is only supported on lower level filters e.g. DeployedExtractionFilter and AggregateFilter");
}
+ public override int Order { get => _order; set => SetField(ref _order,value); }
///
public IHasDependencies[] GetObjectsThisDependsOn()
diff --git a/Rdmp.Core/Curation/Data/Spontaneous/SpontaneouslyInventedFilter.cs b/Rdmp.Core/Curation/Data/Spontaneous/SpontaneouslyInventedFilter.cs
index 8bbadc4f85..dd8458426f 100644
--- a/Rdmp.Core/Curation/Data/Spontaneous/SpontaneouslyInventedFilter.cs
+++ b/Rdmp.Core/Curation/Data/Spontaneous/SpontaneouslyInventedFilter.cs
@@ -1,4 +1,4 @@
-// Copyright (c) The University of Dundee 2018-2019
+// Copyright (c) The University of Dundee 2018-2024
// 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.
@@ -22,6 +22,7 @@ public class SpontaneouslyInventedFilter : ConcreteFilter
{
private readonly MemoryCatalogueRepository _repo;
private readonly ISqlParameter[] _filterParametersIfAny;
+ private int _order =0;
///
/// Creates a new temporary (unsaveable) filter in the given memory
@@ -68,6 +69,8 @@ public SpontaneouslyInventedFilter(MemoryCatalogueRepository repo, IFilter copyF
? _repo.GetObjectByID(FilterContainer_ID.Value)
: null;
+ public override int Order { get => _order; set => SetField(ref _order, value); }
+
public override ColumnInfo GetColumnInfoIfExists() => null;
public override IFilterFactory GetFilterFactory() => null;
diff --git a/Rdmp.Core/DataExport/Data/DeployedExtractionFilter.cs b/Rdmp.Core/DataExport/Data/DeployedExtractionFilter.cs
index d1e7960ade..122eece307 100644
--- a/Rdmp.Core/DataExport/Data/DeployedExtractionFilter.cs
+++ b/Rdmp.Core/DataExport/Data/DeployedExtractionFilter.cs
@@ -1,4 +1,4 @@
-// Copyright (c) The University of Dundee 2018-2019
+// Copyright (c) The University of Dundee 2018-2024
// 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.
@@ -36,6 +36,7 @@ public class DeployedExtractionFilter : ConcreteFilter
private int? _clonedFromExtractionFilterID;
private int? _filterContainerID;
+ private int _order;
///
public override int? ClonedFromExtractionFilter_ID
@@ -69,6 +70,8 @@ public override int? FilterContainer_ID
? Repository.GetObjectByID(FilterContainer_ID.Value)
: null;
+ public override int Order { get => _order; set => SetField(ref _order, value); }
+
#endregion
///
@@ -138,6 +141,7 @@ internal DeployedExtractionFilter(IDataExportRepository repository, DbDataReader
FilterContainer_ID = null;
ClonedFromExtractionFilter_ID = ObjectToNullableInt(r["ClonedFromExtractionFilter_ID"]);
+ Order = int.Parse(r["Order"].ToString());
}
///
diff --git a/Rdmp.Core/Databases/CatalogueDatabase/runAfterCreateDatabase/CreateCatalogue.sql b/Rdmp.Core/Databases/CatalogueDatabase/runAfterCreateDatabase/CreateCatalogue.sql
index e794b1e35c..418fcf7e9d 100644
--- a/Rdmp.Core/Databases/CatalogueDatabase/runAfterCreateDatabase/CreateCatalogue.sql
+++ b/Rdmp.Core/Databases/CatalogueDatabase/runAfterCreateDatabase/CreateCatalogue.sql
@@ -141,6 +141,7 @@ CREATE TABLE [dbo].[AggregateFilter](
[AssociatedColumnInfo_ID] [int] NULL,
[ID] [int] IDENTITY(1,1) NOT NULL,
[SoftwareVersion] [nvarchar](50) NOT NULL,
+ [Order] [int] NOT NULL DEFAULT 0
CONSTRAINT [PK_AggregateFilter] PRIMARY KEY CLUSTERED
(
[ID] ASC
@@ -464,6 +465,7 @@ CREATE TABLE [dbo].[ExtractionFilter](
[Name] [varchar](100) NOT NULL,
[IsMandatory] [bit] NOT NULL,
[SoftwareVersion] [nvarchar](50) NOT NULL,
+ [Order] [int] NOT NULL DEFAULT 0
CONSTRAINT [PK_ExtractionFilter] PRIMARY KEY CLUSTERED
(
[ID] ASC
diff --git a/Rdmp.Core/Databases/CatalogueDatabase/up/087_AddAggregateFilterOrdering.sql b/Rdmp.Core/Databases/CatalogueDatabase/up/087_AddAggregateFilterOrdering.sql
new file mode 100644
index 0000000000..0d3e473416
--- /dev/null
+++ b/Rdmp.Core/Databases/CatalogueDatabase/up/087_AddAggregateFilterOrdering.sql
@@ -0,0 +1,13 @@
+----Version: 8.4.0
+----Description: Add Order to Aggregate Filters
+
+if not exists (select 1 from sys.columns where name = 'Order' and OBJECT_NAME(object_id) = 'AggregateFilter')
+BEGIN
+ALTER TABLE [dbo].[AggregateFilter]
+ADD [Order] [int] NOT NULL DEFAULT 0 WITH VALUES
+END
+if not exists (select 1 from sys.columns where name = 'Order' and OBJECT_NAME(object_id) = 'ExtractionFilter')
+BEGIN
+ALTER TABLE [dbo].[ExtractionFilter]
+ADD [Order] [int] NOT NULL DEFAULT 0 WITH VALUES
+END
\ No newline at end of file
diff --git a/Rdmp.Core/Databases/DataExportDatabase/runAfterCreateDatabase/CreateDataExportManager.sql b/Rdmp.Core/Databases/DataExportDatabase/runAfterCreateDatabase/CreateDataExportManager.sql
index 15f75c2cc4..ac1c03a92a 100644
Binary files a/Rdmp.Core/Databases/DataExportDatabase/runAfterCreateDatabase/CreateDataExportManager.sql and b/Rdmp.Core/Databases/DataExportDatabase/runAfterCreateDatabase/CreateDataExportManager.sql differ
diff --git a/Rdmp.Core/Databases/DataExportDatabase/up/026_AddFilterOrder.sql b/Rdmp.Core/Databases/DataExportDatabase/up/026_AddFilterOrder.sql
new file mode 100644
index 0000000000..1181d65c9b
--- /dev/null
+++ b/Rdmp.Core/Databases/DataExportDatabase/up/026_AddFilterOrder.sql
@@ -0,0 +1,8 @@
+----Version: 8.4.0
+----Description: Add Order to Aggregate Filters
+
+if not exists (select 1 from sys.columns where name = 'Order' and OBJECT_NAME(object_id) = 'DeployedExtractionFilter')
+BEGIN
+ALTER TABLE [dbo].[DeployedExtractionFilter]
+ADD [Order] [int] NOT NULL DEFAULT 0 WITH VALUES
+END
\ No newline at end of file
diff --git a/Rdmp.Core/Rdmp.Core.csproj b/Rdmp.Core/Rdmp.Core.csproj
index 449cc6abdb..3f2209d40d 100644
--- a/Rdmp.Core/Rdmp.Core.csproj
+++ b/Rdmp.Core/Rdmp.Core.csproj
@@ -129,6 +129,7 @@
+
@@ -157,6 +158,7 @@
+
@@ -255,6 +257,7 @@
+
@@ -297,6 +300,7 @@
+
diff --git a/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandReorderFilter.cs b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandReorderFilter.cs
new file mode 100644
index 0000000000..e6483fa5a1
--- /dev/null
+++ b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandReorderFilter.cs
@@ -0,0 +1,62 @@
+// Copyright (c) The University of Dundee 2024-2024
+// 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;
+using Rdmp.Core.MapsDirectlyToDatabaseTable;
+using Rdmp.UI.ItemActivation;
+using System;
+using System.Linq;
+
+namespace Rdmp.UI.CommandExecution.AtomicCommands;
+
+public class ExecuteCommandReorderFilter : BasicUICommandExecution
+{
+ private ConcreteFilter _source;
+ private ConcreteFilter _target;
+ private InsertOption _insertOption;
+
+ public ExecuteCommandReorderFilter(IActivateItems activator, ConcreteFilter source, ConcreteFilter destination, InsertOption insertOption) : base(activator)
+ {
+ _source = source;
+ _target = destination;
+ _insertOption = insertOption;
+ if (_source.FilterContainer_ID is null || _target.FilterContainer_ID is null)
+ {
+ SetImpossible("Both filters must exist within some container in order to be orderable");
+ }
+ if (_source.FilterContainer_ID != _target.FilterContainer_ID)
+ {
+ SetImpossible("Cannot reorder filters as they do not share a parent");
+ }
+ }
+
+ public override void Execute()
+ {
+ var order = _target.Order;
+
+ var filters = _target.FilterContainer.GetFilters().Where(f => f is ConcreteFilter).Select(f => (ConcreteFilter)f).ToArray();
+ Array.Sort(
+ filters,
+ delegate (ConcreteFilter a, ConcreteFilter b) { return a.Order.CompareTo(b.Order); }
+ );
+ if (!filters.All(c => c.Order != order))
+ {
+ foreach (var orderable in filters)
+ {
+ if (orderable.Order < order)
+ orderable.Order--;
+ else if (orderable.Order > order)
+ orderable.Order++;
+ else //collision on order
+ orderable.Order += _insertOption == InsertOption.InsertAbove ? 1 : -1;
+ ((ISaveable)orderable).SaveToDatabase();
+ }
+ }
+ _source.Order = order;
+ _source.SaveToDatabase();
+ Publish(_target.FilterContainer);
+ }
+}
diff --git a/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsConcreteFilter.cs b/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsConcreteFilter.cs
index 93f6fb3c1c..98d290b1b0 100644
--- a/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsConcreteFilter.cs
+++ b/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsConcreteFilter.cs
@@ -5,7 +5,9 @@
// You should have received a copy of the GNU General Public License along with RDMP. If not, see .
using Rdmp.Core.CommandExecution;
+using Rdmp.Core.CommandExecution.Combining;
using Rdmp.Core.Curation.Data;
+using Rdmp.UI.CommandExecution.AtomicCommands;
using Rdmp.UI.ExtractionUIs.FilterUIs;
using Rdmp.UI.ItemActivation;
@@ -24,8 +26,16 @@ public override void Activate(ConcreteFilter target)
ItemActivator.Activate(target);
}
- public override ICommandExecution ProposeExecution(ICombineToMakeCommand cmd, ConcreteFilter target,
- InsertOption insertOption = InsertOption.Default) =>
- //currently nothing can be dropped onto a filter
- null;
+ public override ICommandExecution ProposeExecution(ICombineToMakeCommand cmd, ConcreteFilter targetFilter,
+ InsertOption insertOption = InsertOption.Default)
+ {
+ return cmd switch
+ {
+ FilterCombineable sourceFilterCommand =>
+ !sourceFilterCommand.Filter.Equals(targetFilter) && sourceFilterCommand.Filter is ConcreteFilter && sourceFilterCommand.Filter.FilterContainer_ID == targetFilter.FilterContainer_ID ?
+ new ExecuteCommandReorderFilter(ItemActivator, (ConcreteFilter)sourceFilterCommand.Filter, targetFilter, insertOption)
+ : null,
+ _ => null
+ };
+ }
}
\ No newline at end of file
diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs
index 559a541653..dd904c2b97 100644
--- a/SharedAssemblyInfo.cs
+++ b/SharedAssemblyInfo.cs
@@ -10,6 +10,6 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("8.3.0")]
-[assembly: AssemblyFileVersion("8.3.0")]
-[assembly: AssemblyInformationalVersion("8.3.0")]
\ No newline at end of file
+[assembly: AssemblyVersion("8.4.0")]
+[assembly: AssemblyFileVersion("8.4.0")]
+[assembly: AssemblyInformationalVersion("8.4.0")]
\ No newline at end of file