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

HicServices / RDMP / 6237307473

19 Sep 2023 04:02PM UTC coverage: 57.015% (-0.4%) from 57.44%
6237307473

push

github

web-flow
Feature/rc4 (#1570)

* Syntax tidying
* Dependency updates
* Event handling singletons (ThrowImmediately and co)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: James A Sutherland <>
Co-authored-by: James Friel <jfriel001@dundee.ac.uk>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

10734 of 20259 branches covered (0.0%)

Branch coverage included in aggregate %.

5922 of 5922 new or added lines in 565 files covered. (100.0%)

30687 of 52390 relevant lines covered (58.57%)

7361.8 hits per line

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

49.59
/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandImportFilterContainerTree.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.Collections.Generic;
9
using System.Linq;
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.Providers;
19
using Rdmp.Core.Repositories.Construction;
20
using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision;
21
using SixLabors.ImageSharp;
22
using SixLabors.ImageSharp.PixelFormats;
23

24
namespace Rdmp.Core.CommandExecution.AtomicCommands;
25

26
/// <summary>
27
/// Imports the entire tree from another <see cref="ISelectedDataSets"/> or <see cref="AggregateConfiguration"/> into a given <see cref="SelectedDataSets"/> (as new copies)
28
/// </summary>
29
public class ExecuteCommandImportFilterContainerTree : BasicCommandExecution
30
{
31
    /// <summary>
32
    /// ID of the Catalogue that is being extracted by <see cref="_into"/> to ensure that we only import filters from the same table
33
    /// </summary>
34
    private readonly ICatalogue _catalogue;
35

36
    private readonly IRootFilterContainerHost _into;
37
    private const float DEFAULT_WEIGHT = 1.2f;
38

39
    /// <summary>
40
    /// May be null, if populated this is the explicit subcontainer into which the tree should be imported i.e. not <see cref="_into"/>
41
    /// </summary>
42
    private IContainer _intoSubContainer;
43

44
    /// <summary>
45
    /// May be null, if populated then this is the explicit one the user wants and we shouldn't ask them again
46
    /// </summary>
47
    private IContainer _explicitChoice;
48

49
    private ExecuteCommandImportFilterContainerTree(IBasicActivateItems activator) : base(activator)
6✔
50
    {
51
        Weight = DEFAULT_WEIGHT;
6✔
52

53
        if (activator.CoreChildProvider is not DataExportChildProvider)
6!
54
            SetImpossible("Data export functions unavailable");
×
55
    }
6✔
56

57
    public ExecuteCommandImportFilterContainerTree(IBasicActivateItems activator, IRootFilterContainerHost into) :
58
        this(activator)
6✔
59
    {
60
        Weight = DEFAULT_WEIGHT;
6✔
61

62
        _into = into;
6✔
63

64
        if (into.RootFilterContainer_ID != null)
6!
65
            SetImpossible("Dataset already has a root container");
×
66

67

68
        if (into is AggregateConfiguration ac && ac.Catalogue.IsApiCall())
6!
69
            SetImpossible(ExecuteCommandAddNewFilterContainer.FiltersCannotBeAddedToApiCalls);
×
70

71
        _catalogue = _into.GetCatalogue();
6✔
72

73
        SetImpossibleIfReadonly(into);
6✔
74
    }
6✔
75

76
    /// <summary>
77
    /// constructor for explicit choices, use this aggregates root container
78
    /// </summary>
79
    /// <param name="activator"></param>
80
    /// <param name="into"></param>
81
    /// <param name="from"></param>
82
    [UseWithObjectConstructor]
83
    public ExecuteCommandImportFilterContainerTree(IBasicActivateItems activator, IRootFilterContainerHost into,
84
        IRootFilterContainerHost from) : this(activator, into)
6✔
85
    {
86
        Weight = DEFAULT_WEIGHT;
6✔
87

88
        if (from.RootFilterContainer_ID == null)
6!
89
            SetImpossible("AggregateConfiguration has no root container");
×
90
        else
91
            _explicitChoice = from.RootFilterContainer;
6✔
92
    }
6✔
93

94
    /// <summary>
95
    /// Constructor for explicitly specifying the container to import
96
    /// </summary>
97
    /// <param name="activator"></param>
98
    /// <param name="into"></param>
99
    /// <param name="explicitChoice"></param>
100
    public ExecuteCommandImportFilterContainerTree(IBasicActivateItems activator, IRootFilterContainerHost into,
101
        IContainer explicitChoice) : this(activator, into)
×
102
    {
103
        Weight = DEFAULT_WEIGHT;
×
104

105
        _explicitChoice = explicitChoice;
×
106
    }
×
107

108
    /// <summary>
109
    /// Constructor for importing into a sub container
110
    /// </summary>
111
    /// <param name="activator"></param>
112
    /// <param name="into"></param>
113
    /// <param name="explicitChoice"></param>
114
    public ExecuteCommandImportFilterContainerTree(IBasicActivateItems activator, IContainer into,
115
        IContainer explicitChoice) : this(activator)
×
116
    {
117
        Weight = DEFAULT_WEIGHT;
×
118

119
        _intoSubContainer = into;
×
120
        _explicitChoice = explicitChoice;
×
121
    }
×
122

123
    public override Image<Rgba32> GetImage(IIconProvider iconProvider) =>
124
        iconProvider.GetImage(RDMPConcept.FilterContainer, OverlayKind.Import);
×
125

126
    public override void Execute()
127
    {
128
        base.Execute();
6✔
129

130
        if (_explicitChoice != null)
6!
131
        {
132
            Import(_explicitChoice);
6✔
133
        }
134
        else
135
        {
136
            if (_into == null)
×
137
                throw new NotSupportedException(
×
138
                    "Interactive mode is only supported when specifying a root object to import into");
×
139

140
            //prompt user to pick one
141
            var childProvider = (DataExportChildProvider)BasicActivator.CoreChildProvider;
×
142

143
            var ecById = childProvider.ExtractionConfigurations.ToDictionary(k => k.ID);
×
144

145
            // The root object that makes most sense to the user e.g. they select an extraction
146
            var fromConfiguration
×
147
                =
×
148
                childProvider.AllCohortIdentificationConfigurations.Where(IsEligible)
×
149
                    .Cast<DatabaseEntity>()
×
150
                    .Union(childProvider.SelectedDataSets.Where(IsEligible)
×
151
                        .Select(sds => ecById[sds.ExtractionConfiguration_ID])).ToList();
×
152

153
            if (!fromConfiguration.Any())
×
154
            {
155
                Show("There are no extractions or cohort builder configurations of this dataset that use filters");
×
156
                return;
×
157
            }
158

159
            if (SelectOne(fromConfiguration, out var selected))
×
160
            {
161
                if (selected is ExtractionConfiguration ec) Import(GetEligibleChild(ec).RootFilterContainer);
×
162
                if (selected is CohortIdentificationConfiguration cic)
×
163
                {
164
                    var chosen = SelectOne(GetEligibleChildren(cic).ToList(), null, true);
×
165

166
                    if (chosen != null)
×
167
                        Import(chosen.RootFilterContainer);
×
168
                }
169
            }
170
        }
171

172
        Publish((DatabaseEntity)_into ?? (DatabaseEntity)_intoSubContainer);
6!
173
    }
6✔
174

175
    private void Import(IContainer from)
176
    {
177
        var factory =
6!
178
            _into != null ? _into.GetFilterFactory() : _intoSubContainer.GetFilterFactory();
6✔
179

180
        IContainer intoContainer;
181

182
        if (_into != null)
6!
183
        {
184
            var newRoot = factory.CreateNewContainer();
6✔
185
            newRoot.Operation = from.Operation;
6✔
186
            newRoot.SaveToDatabase();
6✔
187
            _into.RootFilterContainer_ID = newRoot.ID;
6✔
188
            _into.SaveToDatabase();
6✔
189

190
            intoContainer = newRoot;
6✔
191
        }
192
        else
193
        {
194
            intoContainer = _intoSubContainer;
×
195
        }
196

197
        DeepClone(intoContainer, from, factory);
6✔
198
    }
6✔
199

200
    private void DeepClone(IContainer into, IContainer from, IFilterFactory factory)
201
    {
202
        //clone the subcontainers
203
        foreach (var container in from.GetSubContainers())
28✔
204
        {
205
            var subContainer = factory.CreateNewContainer();
4✔
206
            subContainer.Operation = container.Operation;
4✔
207
            subContainer.SaveToDatabase();
4✔
208
            into.AddChild(subContainer);
4✔
209

210
            DeepClone(subContainer, container, factory);
4✔
211
        }
212

213
        var wizard = new FilterImportWizard(BasicActivator);
10✔
214

215
        //clone the filters
216
        foreach (var filter in from.GetFilters())
32✔
217
            into.AddChild(wizard.Import(into, filter));
6✔
218
    }
10✔
219

220
    private bool IsEligible(CohortIdentificationConfiguration arg) => GetEligibleChildren(arg).Any();
×
221

222

223
    /// <summary>
224
    /// Returns all <see cref="AggregateConfiguration"/> from the <paramref name="arg"/> where the dataset is the same and there are filters defined
225
    /// </summary>
226
    /// <param name="arg"></param>
227
    /// <returns></returns>
228
    private IEnumerable<AggregateConfiguration> GetEligibleChildren(CohortIdentificationConfiguration arg)
229
    {
230
        return arg.RootCohortAggregateContainer_ID == null
×
231
            ? Array.Empty<AggregateConfiguration>()
×
232
            : arg.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively()
×
233
                .Where(ac => ac.Catalogue_ID == _catalogue.ID && ac.RootFilterContainer_ID != null);
×
234
    }
235

236
    /// <summary>
237
    /// Returns the <see cref="ISelectedDataSets"/> that matches the dataset <see cref="_into"/> if it is one of the datasets in the <see cref="ExtractionConfiguration"/> <paramref name="arg"/> (each dataset can only be extracted once in a given <see cref="ExtractionConfiguration"/>)
238
    /// </summary>
239
    /// <param name="arg"></param>
240
    /// <returns></returns>
241
    private ISelectedDataSets GetEligibleChild(ExtractionConfiguration arg) =>
242
        arg.SelectedDataSets.FirstOrDefault(IsEligible);
×
243

244
    private bool IsEligible(ISelectedDataSets arg) => arg.RootFilterContainer_ID != null;
×
245
}
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