• 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

85.27
/Rdmp.Core/Repositories/DataExportRepository.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.Data.Common;
10
using System.Linq;
11
using Rdmp.Core.Curation.Data;
12
using Rdmp.Core.DataExport.Data;
13
using Rdmp.Core.DataExport.DataRelease.Audit;
14
using Rdmp.Core.MapsDirectlyToDatabaseTable;
15
using Rdmp.Core.Repositories.Construction;
16
using Rdmp.Core.Repositories.Managers;
17
using Rdmp.Core.ReusableLibraryCode;
18

19
namespace Rdmp.Core.Repositories;
20

21
/// <summary>
22
/// Pointer to the Data Export Repository database in which all export related DatabaseEntities are stored (e.g. ExtractionConfiguration).  Every DatabaseEntity class must exist in a
23
/// Microsoft Sql Server Database (See DatabaseEntity) and each object is compatible only with a specific type of TableRepository (i.e. the database that contains the
24
/// table matching their name).
25
/// 
26
/// <para>This class allows you to fetch objects and should be passed into constructors of classes you want to construct in the Data Export database.  This includes extraction
27
/// Projects, ExtractionConfigurations, ExtractableCohorts etc.</para>
28
/// 
29
/// <para>Data Export databases are only valid when you have a CatalogueRepository database too and are always paired to a specific CatalogueRepository database (i.e. there are
30
/// IDs in the data export database that specifically map to objects in the Catalogue database).  You can use the CatalogueRepository property to fetch/create objects
31
/// in the paired Catalogue database.</para>
32
/// </summary>
33
public class DataExportRepository : TableRepository, IDataExportRepository
34
{
35
    /// <summary>
36
    /// The paired Catalogue database which contains non extract metadata (i.e. datasets, aggregates, data loads etc).  Some objects in this database
37
    /// contain references to objects in the CatalogueRepository.
38
    /// </summary>
39
    public ICatalogueRepository CatalogueRepository { get; private set; }
2,770✔
40

41
    public IFilterManager FilterManager { get; private set; }
406✔
42

43
    public IDataExportPropertyManager DataExportPropertyManager { get; private set; }
484✔
44

45
    private Lazy<Dictionary<int, List<int>>> _packageContentsDictionary;
46

47
    public DataExportRepository(DbConnectionStringBuilder connectionString, ICatalogueRepository catalogueRepository) :
48
        base(null, connectionString)
346✔
49
    {
50
        CatalogueRepository = catalogueRepository;
346✔
51

52
        FilterManager = new DataExportFilterManager(this);
346✔
53

54
        _packageContentsDictionary = new Lazy<Dictionary<int, List<int>>>(GetPackageContentsDictionary);
346✔
55

56
        DataExportPropertyManager = new DataExportPropertyManager(false, this);
346✔
57

58
        Constructors.Add(typeof(SupplementalExtractionResults),
346✔
59
            (rep, r) => new SupplementalExtractionResults((IDataExportRepository)rep, r));
380✔
60
        Constructors.Add(typeof(CumulativeExtractionResults),
346✔
61
            (rep, r) => new CumulativeExtractionResults((IDataExportRepository)rep, r));
766✔
62
        Constructors.Add(typeof(DeployedExtractionFilter),
346✔
63
            (rep, r) => new DeployedExtractionFilter((IDataExportRepository)rep, r));
432✔
64
        Constructors.Add(typeof(DeployedExtractionFilterParameter),
346✔
65
            (rep, r) => new DeployedExtractionFilterParameter((IDataExportRepository)rep, r));
390✔
66
        Constructors.Add(typeof(ExternalCohortTable),
346✔
67
            (rep, r) => new ExternalCohortTable((IDataExportRepository)rep, r));
754✔
68
        Constructors.Add(typeof(ExtractableCohort), (rep, r) => new ExtractableCohort((IDataExportRepository)rep, r));
616✔
69
        Constructors.Add(typeof(ExtractableColumn), (rep, r) => new ExtractableColumn((IDataExportRepository)rep, r));
5,798✔
70
        Constructors.Add(typeof(ExtractableDataSet), (rep, r) => new ExtractableDataSet((IDataExportRepository)rep, r));
992✔
71
        Constructors.Add(typeof(ExtractionConfiguration),
346✔
72
            (rep, r) => new ExtractionConfiguration((IDataExportRepository)rep, r));
986✔
73
        Constructors.Add(typeof(FilterContainer), (rep, r) => new FilterContainer((IDataExportRepository)rep, r));
396✔
74
        Constructors.Add(typeof(GlobalExtractionFilterParameter),
346✔
75
            (rep, r) => new GlobalExtractionFilterParameter((IDataExportRepository)rep, r));
352✔
76
        Constructors.Add(typeof(Project), (rep, r) => new Project((IDataExportRepository)rep, r));
1,302✔
77
        Constructors.Add(typeof(SelectedDataSets), (rep, r) => new SelectedDataSets((IDataExportRepository)rep, r));
1,646✔
78
        Constructors.Add(typeof(ExtractableDataSetPackage),
346✔
79
            (rep, r) => new ExtractableDataSetPackage((IDataExportRepository)rep, r));
350✔
80
        Constructors.Add(typeof(ProjectCohortIdentificationConfigurationAssociation),
346✔
81
            (rep, r) => new ProjectCohortIdentificationConfigurationAssociation((IDataExportRepository)rep, r));
346✔
82
        Constructors.Add(typeof(SelectedDataSetsForcedJoin),
346✔
83
            (rep, r) => new SelectedDataSetsForcedJoin((IDataExportRepository)rep, r));
350✔
84
    }
346✔
85

86
    public IEnumerable<ICumulativeExtractionResults> GetAllCumulativeExtractionResultsFor(
87
        IExtractionConfiguration configuration, IExtractableDataSet dataset) =>
88
        GetAllObjects<CumulativeExtractionResults>(
62✔
89
            $"WHERE ExtractionConfiguration_ID={configuration.ID}AND ExtractableDataSet_ID={dataset.ID}");
62✔
90

91
    private readonly ObjectConstructor _constructor = new();
346✔
92

93
    protected override IMapsDirectlyToDatabaseTable ConstructEntity(Type t, DbDataReader reader) =>
94
        Constructors.TryGetValue(t, out var constructor)
10,448✔
95
            ? constructor(this, reader)
10,448✔
96
            : ObjectConstructor.ConstructIMapsDirectlyToDatabaseObject<IDataExportRepository>(t, this, reader);
10,448✔
97

98
    public CatalogueExtractabilityStatus GetExtractabilityStatus(ICatalogue c)
99
    {
100
        var eds = GetAllObjectsWithParent<ExtractableDataSet>(c).SingleOrDefault();
×
101
        return eds == null ? new CatalogueExtractabilityStatus(false, false) : eds.GetCatalogueExtractabilityStatus();
×
102
    }
103

104
    public ISelectedDataSets[] GetSelectedDatasetsWithNoExtractionIdentifiers() =>
105
        SelectAll<SelectedDataSets>(@"
140✔
106
SELECT ID  FROM SelectedDataSets sds
140✔
107
where not exists (
140✔
108
select 1 FROM ExtractableColumn ec where 
140✔
109
ec.ExtractableDataSet_ID = sds.ExtractableDataSet_ID
140✔
110
AND
140✔
111
ec.IsExtractionIdentifier = 1
140✔
112
AND
140✔
113
ec.ExtractionConfiguration_ID = sds.ExtractionConfiguration_ID
140✔
114
)", "ID").ToArray();
140✔
115

116
    private readonly Dictionary<Type, IRowVerCache> _caches = new();
346✔
117

118
    public override T[] GetAllObjects<T>()
119
    {
120
        if (!_caches.ContainsKey(typeof(T)))
1,796✔
121
            _caches.Add(typeof(T), new RowVerCache<T>(this));
588✔
122

123
        return _caches[typeof(T)].GetAllObjects<T>();
1,796✔
124
    }
125

126
    public override T[] GetAllObjectsNoCache<T>() => base.GetAllObjects<T>();
1,640✔
127

128

129
    /// <inheritdoc/>
130
    public IExtractableDataSet[] GetAllDataSets(IExtractableDataSetPackage package, IExtractableDataSet[] allDataSets)
131
    {
132
        //we know of no children
133
        return !_packageContentsDictionary.Value.TryGetValue(package.ID, out var contents)
4✔
134
            ? Array.Empty<IExtractableDataSet>()
4✔
135
            : contents.Select(i => allDataSets.Single(ds => ds.ID == i)).ToArray();
8✔
136
    }
137

138

139
    public Dictionary<int, List<int>> GetPackageContentsDictionary()
140
    {
141
        var toReturn = new Dictionary<int, List<int>>();
2✔
142

143
        using var con = GetConnection();
2✔
144
        using var r = DiscoveredServer
2✔
145
            .GetCommand(
2✔
146
                "SELECT * FROM ExtractableDataSetPackage_ExtractableDataSet ORDER BY ExtractableDataSetPackage_ID", con)
2✔
147
            .ExecuteReader();
2✔
148

149
        var lastPackageId = -1;
2✔
150
        while (r.Read())
2!
151
        {
152
            var packageID = Convert.ToInt32(r["ExtractableDataSetPackage_ID"]);
×
153
            var dataSetID = Convert.ToInt32(r["ExtractableDataSet_ID"]);
×
154

155
            if (lastPackageId != packageID)
×
156
            {
157
                toReturn.Add(packageID, new List<int>());
×
158
                lastPackageId = packageID;
×
159
            }
160

161
            toReturn[packageID].Add(dataSetID);
×
162
        }
163

164
        return toReturn;
2✔
165
    }
2✔
166

167
    /// <summary>
168
    /// Adds the given <paramref name="dataSet"/> to the <paramref name="package"/> and updates the cached package contents
169
    /// in memory.
170
    /// 
171
    /// <para>This change is immediately written to the database</para>
172
    ///
173
    ///  <para>Throws ArgumentException if the <paramref name="dataSet"/> is already part of the package</para>
174
    /// </summary>
175
    /// <param name="package"></param>
176
    /// <param name="dataSet"></param>
177
    public void AddDataSetToPackage(IExtractableDataSetPackage package, IExtractableDataSet dataSet)
178
    {
179
        if (_packageContentsDictionary.Value.TryGetValue(package.ID, out var contents))
2!
180
        {
181
            if (contents.Contains(dataSet.ID))
×
182
                throw new ArgumentException($"dataSet {dataSet} is already part of package '{package}'",
×
183
                    nameof(dataSet));
×
184
        }
185
        else
186
        {
187
            _packageContentsDictionary.Value.Add(package.ID, new List<int>());
2✔
188
        }
189

190
        using (var con = GetConnection())
2✔
191
        {
192
            DiscoveredServer.GetCommand(
2✔
193
                $"INSERT INTO ExtractableDataSetPackage_ExtractableDataSet(ExtractableDataSetPackage_ID,ExtractableDataSet_ID) VALUES ({package.ID},{dataSet.ID})",
2✔
194
                con).ExecuteNonQuery();
2✔
195
        }
2✔
196

197
        _packageContentsDictionary.Value[package.ID].Add(dataSet.ID);
2✔
198
    }
2✔
199

200

201
    /// <summary>
202
    /// Removes the given <paramref name="dataSet"/> from the <paramref name="package"/> and updates the cached package contents
203
    /// in memory.
204
    /// 
205
    /// <para>This change is immediately written to the database</para>
206
    ///
207
    ///  <para>Throws ArgumentException if the <paramref name="dataSet"/> is not part of the package</para>
208
    /// </summary>
209
    /// <param name="package"></param>
210
    /// <param name="dataSet"></param>
211
    public void RemoveDataSetFromPackage(IExtractableDataSetPackage package, IExtractableDataSet dataSet)
212
    {
213
        if (!_packageContentsDictionary.Value[package.ID].Contains(dataSet.ID))
4✔
214
            throw new ArgumentException($"dataSet {dataSet} is not part of package {package} so cannot be removed",
2✔
215
                nameof(dataSet));
2✔
216

217
        using (var con = GetConnection())
2✔
218
        {
219
            DiscoveredServer.GetCommand(
2✔
220
                $"DELETE FROM ExtractableDataSetPackage_ExtractableDataSet WHERE ExtractableDataSetPackage_ID = {package.ID} AND ExtractableDataSet_ID ={dataSet.ID}",
2✔
221
                con).ExecuteNonQuery();
2✔
222
        }
2✔
223

224
        _packageContentsDictionary.Value[package.ID].Remove(dataSet.ID);
2✔
225
    }
2✔
226

227
    public IReleaseLog GetReleaseLogEntryIfAny(CumulativeExtractionResults cumulativeExtractionResults)
228
    {
229
        using var con = GetConnection();
26✔
230
        using var cmdselect = DatabaseCommandHelper
26✔
231
            .GetCommand($@"SELECT *
26✔
232
                                    FROM ReleaseLog
26✔
233
                                    where
26✔
234
                                    CumulativeExtractionResults_ID = {cumulativeExtractionResults.ID}", con.Connection,
26✔
235
                con.Transaction);
26✔
236
        using var r = cmdselect.ExecuteReader();
26✔
237
        return r.Read() ? new ReleaseLog(this, r) : null;
26!
238
    }
26✔
239
}
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