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

HicServices / RDMP / 17492976312

05 Sep 2025 12:20PM UTC coverage: 57.447% (-0.006%) from 57.453%
17492976312

push

github

web-flow
allow use of cic filters in extractions (#2221)

11429 of 21419 branches covered (53.36%)

Branch coverage included in aggregate %.

0 of 11 new or added lines in 1 file covered. (0.0%)

2 existing lines in 1 file now uncovered.

32397 of 54870 relevant lines covered (59.04%)

17708.51 hits per line

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

43.54
/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; }
6✔
33
    public ExtractionFilterParameterSet ParameterSet { get; set; }
×
34
    public string Name { get; }
8✔
35
    public string WhereSQL { get; }
8✔
36

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

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

49
    private ExecuteCommandCreateNewFilter(IBasicActivateItems activator) : base(activator)
6✔
50
    {
51
        Weight = DEFAULT_WEIGHT;
6✔
52
    }
6✔
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)
6✔
63
    {
64
        if (picker.Length == 0)
6!
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)
6✔
69
        {
70
            if (picker[0].HasValueOfType(typeof(ExtractionInformation)))
6✔
71
            {
72
                // create a top level Catalogue level filter for reuse later on
73
                var ei = (ExtractionInformation)picker[0].GetValueForParameterOfType(typeof(ExtractionInformation));
2✔
74
                _factory = new ExtractionFilterFactory(ei);
2✔
75
            }
76
            else if (picker[0].HasValueOfType(typeof(IContainer)))
4!
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)))
4!
83
            {
84
                // create a container (if none) then add filter to root container of the object
85
                _host = (IRootFilterContainerHost)picker[0]
4✔
86
                    .GetValueForParameterOfType(typeof(IRootFilterContainerHost));
4✔
87
                SetImpossibleIfReadonly(_host);
4✔
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();
6!
97

98
            if (_factory == null)
6!
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;
6✔
104

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

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

119
        if (picker.Length > stringArgsStartAt) Name = picker[stringArgsStartAt].RawValue;
8✔
120
        if (picker.Length > stringArgsStartAt + 1) WhereSQL = picker[stringArgsStartAt + 1].RawValue;
8✔
121
    }
6✔
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();
6✔
184

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

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

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

196

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

NEW
206
            var c = GetCatalogue();
×
NEW
207
            _offerFilters = c?.GetAllFilters();
×
NEW
208
            if (_host is SelectedDataSets sds)
×
209
            {
NEW
210
                var cohortId = sds.ExtractionConfiguration.Cohort.OriginID;
×
NEW
211
                var cic = c.CatalogueRepository.GetObjectByID<CohortIdentificationConfiguration>(cohortId);
×
NEW
212
                if (cic != null)
×
213
                {
NEW
214
                    var filters = cic.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().SelectMany(ac => ac.RootFilterContainer.GetAllFiltersIncludingInSubContainersRecursively());
×
NEW
215
                    filters = filters.Where(f => f.GetCatalogue().ID == c.ID);
×
NEW
216
                    _offerFilters = _offerFilters.Concat(filters).ToArray();
×
217
                }
218
            }
NEW
219
            if (_offerFilters == null || !_offerFilters.Any())
×
NEW
220
                SetImpossible($"There are no Filters declared in Catalogue '{c?.ToString() ?? "NULL"}'");
×
221

222
            // we want user to make decision about what to import
223
            ImportExistingFilter(container);
×
224
            return;
×
225
        }
226
        else
227
        {
228
            f = _factory.CreateNewFilter($"New Filter {Guid.NewGuid()}");
6✔
229
        }
230

231
        container?.AddChild(f);
6✔
232

233
        if (!string.IsNullOrWhiteSpace(Name)) f.Name = Name;
8✔
234
        if (!string.IsNullOrWhiteSpace(WhereSQL)) f.WhereSQL = WhereSQL;
8✔
235

236
        f.SaveToDatabase();
6✔
237

238
        if (f is ExtractionFilter ef)
6✔
239
            Publish(ef.ExtractionInformation);
2✔
240
        else
241
            Publish((DatabaseEntity)container ?? (DatabaseEntity)f);
4!
242

243
        Emphasise(f);
6✔
244
        Activate((DatabaseEntity)f);
6✔
245
    }
6✔
246

247
    private void ImportExistingFilter(IContainer container)
248
    {
249
        var wizard = new FilterImportWizard(BasicActivator);
×
250

251
        var filters = _offerFilters;
×
252
        var import = wizard.ImportManyFromSelection(container, filters).ToArray();
×
253

254
        foreach (var f in import) container.AddChild(f);
×
255

256
        if (import.Length > 0)
×
257
        {
258
            Publish((DatabaseEntity)container);
×
259
            Emphasise((DatabaseEntity)import.Last());
×
260
        }
261
    }
×
262
}
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