• 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

59.78
/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandAddPipelineComponent.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.Data;
11
using Rdmp.Core.Curation.Data.Pipelines;
12
using Rdmp.Core.DataFlowPipeline;
13
using Rdmp.Core.Icons.IconProvision;
14
using Rdmp.Core.Repositories.Construction;
15
using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision;
16
using SixLabors.ImageSharp;
17
using SixLabors.ImageSharp.PixelFormats;
18

19
namespace Rdmp.Core.CommandExecution.AtomicCommands;
20

21
/// <summary>
22
/// Adds new <see cref="PipelineComponent"/> to an existing <see cref="Pipeline"/>
23
/// </summary>
24
public class ExecuteCommandAddPipelineComponent : BasicCommandExecution
25
{
26
    private readonly IPipeline _pipeline;
27
    private readonly Type _toAdd;
28
    private readonly int? _order;
29
    private readonly IPipelineUseCase _useCaseIfAny;
30

31
    [UseWithObjectConstructor]
32
    public ExecuteCommandAddPipelineComponent(IBasicActivateItems activator,
33
        [DemandsInitialization("The pipeline to add the component to")]
34
        IPipeline pipeline,
35
        [DemandsInitialization("The Type of component to add")]
36
        Type toAdd,
37
        [DemandsInitialization("The position in the pipeline to place the component relative to other components.")]
38
        int? order = null) : base(activator)
16✔
39
    {
40
        _pipeline = pipeline;
16✔
41
        _toAdd = toAdd;
16✔
42
        _order = order;
16✔
43
    }
16✔
44

45
    public ExecuteCommandAddPipelineComponent(IBasicActivateItems activator, IPipeline pipeline,
46
        IPipelineUseCase useCaseIfAny) : base(activator)
×
47
    {
48
        _pipeline = pipeline;
×
49
        _useCaseIfAny = useCaseIfAny;
×
50
    }
×
51

52
    public override Image<Rgba32> GetImage(IIconProvider iconProvider) =>
53
        iconProvider.GetImage(RDMPConcept.PipelineComponent, OverlayKind.Add);
×
54

55
    public override void Execute()
56
    {
57
        base.Execute();
16✔
58
        var add = _toAdd;
16✔
59
        var order = _order;
16✔
60

61
        // if command doesn't know which to add, ask user
62
        if (add == null)
16!
63
        {
64
            var context = _useCaseIfAny?.GetContext();
×
65
            var offer = new List<Type>();
×
66

67
            bool Filter(Type t, object o) => t.IsGenericType &&
×
68
                                             (t.GetGenericTypeDefinition() == typeof(IDataFlowComponent<>) ||
×
69
                                              t.GetGenericTypeDefinition() == typeof(IDataFlowSource<>));
×
70

71
            //get any source and flow components compatible with any context
72
            offer.AddRange(
×
73
                Repositories.MEF.GetAllTypes()
×
74
                    .Where(t => !t.IsInterface && !t.IsAbstract)
×
75
                    .Where(t => t.FindInterfaces(Filter, null).Any())
×
76
                    .Where(t => context == null || context.IsAllowable(t))
×
77
            );
×
78

79
            if (!BasicActivator.SelectObject("Add", offer.ToArray(), out add))
×
80
                return;
×
81
        }
82

83
        // Only proceed if we have a component type to add to the pipe
84
        if (add == null) return;
16!
85

86
        var isSource = add.FindInterfaces(SourceFilter, null).Any();
16✔
87
        var isDest = add.FindInterfaces(DestFilter, null).Any();
16✔
88

89
        if (isSource)
16✔
90
        {
91
            order = int.MinValue;
6✔
92
            if (_pipeline.SourcePipelineComponent_ID.HasValue)
6✔
93
                throw new Exception($"Pipeline '{_pipeline}' already has a source");
2✔
94
        }
95

96
        if (isDest)
14✔
97
        {
98
            order = int.MaxValue;
6✔
99
            if (_pipeline.DestinationPipelineComponent_ID.HasValue)
6✔
100
                throw new Exception($"Pipeline '{_pipeline}' already has a destination");
2✔
101
        }
102

103
        // if we don't know the order yet and it's important
104
        if (!order.HasValue)
12!
105
        {
106
            if (BasicActivator.SelectValueType("Order", typeof(int), 0, out var chosen))
×
107
                order = (int)chosen;
×
108
            else
109
                return;
×
110
        }
111

112
        var newComponent = new PipelineComponent(BasicActivator.RepositoryLocator.CatalogueRepository, _pipeline,
12✔
113
            add, (int)order);
12✔
114
        newComponent.CreateArgumentsForClassIfNotExists(add);
12✔
115

116
        if (isSource)
12✔
117
        {
118
            _pipeline.SourcePipelineComponent_ID = newComponent.ID;
4✔
119
            _pipeline.SaveToDatabase();
4✔
120
        }
121

122
        if (isDest)
12✔
123
        {
124
            _pipeline.DestinationPipelineComponent_ID = newComponent.ID;
4✔
125
            _pipeline.SaveToDatabase();
4✔
126
        }
127

128
        Publish(newComponent);
12✔
129
        Emphasise(newComponent);
12✔
130
        return;
12✔
131

132
        // check if it is a source or destination (or if both are false it is a middle component)
133
        bool SourceFilter(Type t, object o) =>
134
            t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IDataFlowSource<>);
90✔
135

136
        bool DestFilter(Type t, object o) =>
137
            t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IDataFlowDestination<>);
90✔
138
    }
139
}
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