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

HicServices / RDMP / 9859858140

09 Jul 2024 03:24PM UTC coverage: 56.679% (-0.2%) from 56.916%
9859858140

push

github

JFriel
update

10912 of 20750 branches covered (52.59%)

Branch coverage included in aggregate %.

30965 of 53135 relevant lines covered (58.28%)

7908.05 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
            static bool Filter(Type t, object o)
68
            {
69
                return t.IsGenericType &&
×
70
                       (t.GetGenericTypeDefinition() == typeof(IDataFlowComponent<>) ||
×
71
                        t.GetGenericTypeDefinition() == typeof(IDataFlowSource<>));
×
72
            }
73

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

82
            if (!BasicActivator.SelectObject("Add", offer.ToArray(), out add))
×
83
                return;
×
84
        }
85

86
        // Only proceed if we have a component type to add to the pipe
87
        if (add == null) return;
16!
88

89
        var isSource = add.FindInterfaces(SourceFilter, null).Any();
16✔
90
        var isDest = add.FindInterfaces(DestFilter, null).Any();
16✔
91

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

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

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

115
        var newComponent = new PipelineComponent(BasicActivator.RepositoryLocator.CatalogueRepository, _pipeline,
12✔
116
            add, (int)order);
12✔
117
        newComponent.CreateArgumentsForClassIfNotExists(add);
12✔
118

119
        if (isSource)
12✔
120
        {
121
            _pipeline.SourcePipelineComponent_ID = newComponent.ID;
4✔
122
            _pipeline.SaveToDatabase();
4✔
123
        }
124

125
        if (isDest)
12✔
126
        {
127
            _pipeline.DestinationPipelineComponent_ID = newComponent.ID;
4✔
128
            _pipeline.SaveToDatabase();
4✔
129
        }
130

131
        Publish(newComponent);
12✔
132
        Emphasise(newComponent);
12✔
133
        return;
12✔
134

135
        // check if it is a source or destination (or if both are false it is a middle component)
136
        static bool SourceFilter(Type t, object o)
137
        {
138
            return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IDataFlowSource<>);
90✔
139
        }
140

141
        static bool DestFilter(Type t, object o)
142
        {
143
            return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IDataFlowDestination<>);
90✔
144
        }
145
    }
146
}
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