• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

HicServices / RDMP / 20057586828

09 Dec 2025 08:56AM UTC coverage: 57.193% (-0.2%) from 57.422%
20057586828

Pull #2182

github

JFriel
Merge branch 'develop' of https://github.com/HicServices/RDMP into task/RDMP-33-dataset-integration-interface
Pull Request #2182: [Datasets] Task/rdmp 33 dataset integration interface

11510 of 21615 branches covered (53.25%)

Branch coverage included in aggregate %.

1226 of 2024 new or added lines in 85 files covered. (60.57%)

35 existing lines in 15 files now uncovered.

32654 of 55604 relevant lines covered (58.73%)

8854.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.96
/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewFilter.cs
1
// Copyright (c) The University of Dundee 2018-2019
2
// This file is part of the Research Data Management Platform (RDMP).
3
// 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.
4
// 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.
5
// You should have received a copy of the GNU General Public License along with RDMP. If not, see <https://www.gnu.org/licenses/>.
6

7
using System;
8
using System.Linq;
9
using Rdmp.Core.CommandLine.Interactive.Picking;
10
using Rdmp.Core.Curation;
11
using Rdmp.Core.Curation.Data;
12
using Rdmp.Core.Curation.Data.Aggregation;
13
using Rdmp.Core.Curation.Data.Cohort;
14
using Rdmp.Core.Curation.FilterImporting;
15
using Rdmp.Core.Curation.FilterImporting.Construction;
16
using Rdmp.Core.DataExport.Data;
17
using Rdmp.Core.Icons.IconProvision;
18
using Rdmp.Core.Repositories.Construction;
19
using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision;
20
using SixLabors.ImageSharp;
21
using SixLabors.ImageSharp.PixelFormats;
22

23
namespace Rdmp.Core.CommandExecution.AtomicCommands;
24

25
public class ExecuteCommandCreateNewFilter : BasicCommandExecution, IAtomicCommand
26
{
27
    private IFilterFactory _factory;
28
    private IContainer _container;
29
    private IRootFilterContainerHost _host;
30
    private const float DEFAULT_WEIGHT = 0.1f;
31

32
    public IFilter BasedOn { get; set; }
3✔
33
    public ExtractionFilterParameterSet ParameterSet { get; set; }
×
34
    public string Name { get; }
4✔
35
    public string WhereSQL { get; }
4✔
36

37
    private IFilter[] _offerFilters = [];
3✔
38
    private bool offerCatalogueFilters;
39

40
    public bool OfferCatalogueFilters
41
    {
42
        get => offerCatalogueFilters;
3✔
43
        set
44
        {
45
            offerCatalogueFilters = value;
×
UNCOV
46
        }
×
47
    }
48

49
    private ExecuteCommandCreateNewFilter(IBasicActivateItems activator) : base(activator)
3✔
50
    {
51
        Weight = DEFAULT_WEIGHT;
3✔
52
    }
3✔
53

54
    [UseWithCommandLine(
55
        ParameterHelpList = "<into> <basedOn> <name> <where>",
56
        ParameterHelpBreakdown =
57
            @"into        A WHERE filter container or IRootFilterContainerHost (e.g. AggregateConfiguration)
58
basedOn    Optional ExtractionFilter to copy or ExtractionFilterParameterSet
59
name    Optional name to set for the new filter
60
where    Optional SQL to set for the filter.  If <basedOn> is not null this will overwrite it")]
61
    public ExecuteCommandCreateNewFilter(IBasicActivateItems activator,
62
        CommandLineObjectPicker picker) : this(activator)
3✔
63
    {
64
        if (picker.Length == 0)
3!
65
            throw new ArgumentException(
×
66
                "You must supply at least one argument to this command (where you want to create the filter)");
×
67

68
        if (picker.Length > 0)
3✔
69
        {
70
            if (picker[0].HasValueOfType(typeof(ExtractionInformation)))
3✔
71
            {
72
                // create a top level Catalogue level filter for reuse later on
73
                var ei = (ExtractionInformation)picker[0].GetValueForParameterOfType(typeof(ExtractionInformation));
1✔
74
                _factory = new ExtractionFilterFactory(ei);
1✔
75
            }
76
            else if (picker[0].HasValueOfType(typeof(IContainer)))
2!
77
            {
78
                // create a filter in this container
79
                _container = (IContainer)picker[0].GetValueForParameterOfType(typeof(IContainer));
×
80
                SetImpossibleIfReadonly(_container);
×
81
            }
82
            else if (picker[0].HasValueOfType(typeof(IRootFilterContainerHost)))
2!
83
            {
84
                // create a container (if none) then add filter to root container of the object
85
                _host = (IRootFilterContainerHost)picker[0]
2✔
86
                    .GetValueForParameterOfType(typeof(IRootFilterContainerHost));
2✔
87
                SetImpossibleIfReadonly(_host);
2✔
88
            }
89
            else
90
            {
91
                throw new ArgumentException(
×
92
                    $"First argument must be {nameof(IContainer)} or  {nameof(IRootFilterContainerHost)} but it was '{picker[0].RawValue}'");
×
93
            }
94

95

96
            _factory ??= _container?.GetFilterFactory() ?? _host?.GetFilterFactory();
3!
97

98
            if (_factory == null)
3!
99
                throw new Exception("It was not possible to work out a FilterFactory from the container/host");
×
100
        }
101

102
        // the index that string arguments begin at (Name and WhereSql)
103
        var stringArgsStartAt = 2;
3✔
104

105
        if (picker.Length > 1)
3✔
106
        {
107
            if (IsImpossible)
1!
108
                return;
×
109

110
            if (picker[1].HasValueOfType(typeof(IFilter)))
1!
111
                BasedOn = (IFilter)picker[1].GetValueForParameterOfType(typeof(IFilter));
×
112
            else if (picker[1].HasValueOfType(typeof(ExtractionFilterParameterSet)))
1!
113
                ParameterSet =
×
114
                    (ExtractionFilterParameterSet)picker[1]
×
115
                        .GetValueForParameterOfType(typeof(ExtractionFilterParameterSet));
×
116
            else if (!picker[1].ExplicitNull) stringArgsStartAt = 1;
2✔
117
        }
118

119
        if (picker.Length > stringArgsStartAt) Name = picker[stringArgsStartAt].RawValue;
4✔
120
        if (picker.Length > stringArgsStartAt + 1) WhereSQL = picker[stringArgsStartAt + 1].RawValue;
4✔
121
    }
3✔
122

123

124
    public ExecuteCommandCreateNewFilter(IBasicActivateItems activator, IRootFilterContainerHost host) : this(activator)
×
125
    {
126
        _factory = host.GetFilterFactory();
×
127
        _container = host.RootFilterContainer;
×
128
        _host = host;
×
UNCOV
129
        if (_container == null && _host is AggregateConfiguration ac)
×
130
        {
131
            if (ac.Catalogue.IsApiCall())
×
132
                SetImpossible(ExecuteCommandAddNewFilterContainer.FiltersCannotBeAddedToApiCalls);
×
133

134
            if (ac.OverrideFiltersByUsingParentAggregateConfigurationInstead_ID != null)
×
135
                SetImpossible("Aggregate is set to use another's filter container tree");
×
136
        }
137

138
        SetImpossibleIfReadonly(host);
×
139
    }
×
140

141

142
    public ExecuteCommandCreateNewFilter(IBasicActivateItems activator, CatalogueItem ci) : this(activator)
×
143
    {
144
        if (ci.ExtractionInformation == null)
×
145
        {
146
            SetImpossible(
×
147
                "CatalogueItem is not extractable so cannot have filters. Make this CatalogueItem extractable to add filters.");
×
148
            return;
×
149
        }
150

151
        _factory = new ExtractionFilterFactory(ci.ExtractionInformation);
×
152
    }
×
153

154
    public ExecuteCommandCreateNewFilter(IBasicActivateItems activator, IFilterFactory factory,
155
        IContainer container = null)
156
        : this(activator)
×
157
    {
158
        _factory = factory;
×
159
        _container = container;
×
160

161
        SetImpossibleIfReadonly(container);
×
162
    }
×
163

164
    public ExecuteCommandCreateNewFilter(IBasicActivateItems activator, IContainer container, IFilter basedOn) :
165
        this(activator)
×
166
    {
167
        _container = container;
×
168
        BasedOn = basedOn;
×
169

170
        SetImpossibleIfReadonly(container);
×
171
    }
×
172

173

174
    private ICatalogue GetCatalogue() => _host?.GetCatalogue() ?? _container?.GetCatalogueIfAny();
×
175

176
    public override Image<Rgba32> GetImage(IIconProvider iconProvider) =>
177
        OfferCatalogueFilters
×
178
            ? iconProvider.GetImage(RDMPConcept.Filter, OverlayKind.Import)
×
179
            : iconProvider.GetImage(RDMPConcept.Filter, OverlayKind.Add);
×
180

181
    public override void Execute()
182
    {
183
        base.Execute();
3✔
184

185
        IFilter f;
186
        var container = _container;
3✔
187

188
        if (_host != null && container == null)
3✔
189
        {
190
            if (_host.RootFilterContainer_ID == null)
2✔
191
                _host.CreateRootContainerIfNotExists();
2✔
192

193
            container = _host.RootFilterContainer;
2✔
194
        }
195

196

197
        // if importing an existing filter instead of creating blank
198
        if (BasedOn != null)
3!
199
        {
200
            var wizard = new FilterImportWizard(BasicActivator);
×
201
            f = wizard.Import(container, BasedOn, ParameterSet);
×
202
        }
203
        else if (OfferCatalogueFilters)
3!
204
        {
205

NEW
206
            var c = GetCatalogue();
×
NEW
207
            _offerFilters = c?.GetAllFilters();
×
NEW
208
            if (_offerFilters == null || !_offerFilters.Any())
×
NEW
209
                SetImpossible($"There are no Filters declared in Catalogue '{c?.ToString() ?? "NULL"}'");
×
210

211
            // we want user to make decision about what to import
212
            ImportExistingFilter(container);
×
213
            return;
×
214
        }
215
        else
216
        {
217
            f = _factory.CreateNewFilter($"New Filter {Guid.NewGuid()}");
3✔
218
        }
219

220
        container?.AddChild(f);
3✔
221

222
        if (!string.IsNullOrWhiteSpace(Name)) f.Name = Name;
4✔
223
        if (!string.IsNullOrWhiteSpace(WhereSQL)) f.WhereSQL = WhereSQL;
4✔
224

225
        f.SaveToDatabase();
3✔
226

227
        if (f is ExtractionFilter ef)
3✔
228
            Publish(ef.ExtractionInformation);
1✔
229
        else
230
            Publish((DatabaseEntity)container ?? (DatabaseEntity)f);
2!
231

232
        Emphasise(f);
3✔
233
        Activate((DatabaseEntity)f);
3✔
234
    }
3✔
235

236
    private void ImportExistingFilter(IContainer container)
237
    {
238
        var wizard = new FilterImportWizard(BasicActivator);
×
239

NEW
240
        var filters = _offerFilters;
×
241
        var import = wizard.ImportManyFromSelection(container, filters).ToArray();
×
242

243
        foreach (var f in import) container.AddChild(f);
×
244

245
        if (import.Length > 0)
×
246
        {
247
            Publish((DatabaseEntity)container);
×
248
            Emphasise((DatabaseEntity)import.Last());
×
249
        }
250
    }
×
251
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc