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

HicServices / RDMP / 6245535001

20 Sep 2023 07:44AM UTC coverage: 57.013%. First build
6245535001

push

github

web-flow
8.1.0 Release (#1628)

* Bump Newtonsoft.Json from 13.0.1 to 13.0.2

Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 13.0.1 to 13.0.2.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/13.0.1...13.0.2)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump NLog from 5.0.5 to 5.1.0

Bumps [NLog](https://github.com/NLog/NLog) from 5.0.5 to 5.1.0.
- [Release notes](https://github.com/NLog/NLog/releases)
- [Changelog](https://github.com/NLog/NLog/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/NLog/NLog/compare/v5.0.5...v5.1.0)

---
updated-dependencies:
- dependency-name: NLog
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump NLog from 5.0.5 to 5.1.0

* Fix -r flag - should have been --results-directory all along

* Bump Newtonsoft.Json from 13.0.1 to 13.0.2

* Bump YamlDotNet from 12.0.2 to 12.1.0

Bumps [YamlDotNet](https://github.com/aaubry/YamlDotNet) from 12.0.2 to 12.1.0.
- [Release notes](https://github.com/aaubry/YamlDotNet/releases)
- [Commits](https://github.com/aaubry/YamlDotNet/compare/v12.0.2...v12.1.0)

---
updated-dependencies:
- dependency-name: YamlDotNet
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump Moq from 4.18.2 to 4.18.3

Bumps [Moq](https://github.com/moq/moq4) from 4.18.2 to 4.18.3.
- [Release notes](https://github.com/moq/moq4/releases)
- [Changelog](https://github.com/moq/moq4/blob/main/CHANGELOG.md)
- [Commits](https://github.com/moq/moq4/compare/v4.18.2...v4.18.3)

---
updated-dependencies:
- dependency-name: Moq
... (continued)

10732 of 20257 branches covered (0.0%)

Branch coverage included in aggregate %.

48141 of 48141 new or added lines in 1086 files covered. (100.0%)

30685 of 52388 relevant lines covered (58.57%)

7387.88 hits per line

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

92.13
/Rdmp.Core/DataExport/Data/ExtractableColumn.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 Rdmp.Core.Curation.Data;
11
using Rdmp.Core.MapsDirectlyToDatabaseTable;
12
using Rdmp.Core.MapsDirectlyToDatabaseTable.Injection;
13
using Rdmp.Core.QueryBuilding;
14
using Rdmp.Core.Repositories;
15
using Rdmp.Core.ReusableLibraryCode.Annotations;
16

17
namespace Rdmp.Core.DataExport.Data;
18

19
/// <summary>
20
/// Sometimes when extracting data in an ExtractionConfiguration of a Project you don't want to extract all the available (extractable) columns in a dataset.  For example you might
21
/// have some columns which require 'special approval' to be released and most extracts will not include the columns.  ExtractableColumn is the object which records which columns in
22
/// a given ExtractionConfiguration are being released to the researcher.  It also allows you to change the implementation of the column, for example a given researcher might want
23
/// all values UPPERd or he might want the Value field of Prescribing to be passed through his adjustment Scalar Valued Function.
24
/// 
25
/// <para>When selecting a column for extraction in ExtractionConfigurationUI an ExtractableColumn will be created with a pointer to the original ExtractionInformation
26
/// (CatalogueExtractionInformation_ID) in the Catalogue database.  The ExtractionInformations SelectSQL will also be copied out.  The ExtractionQueryBuilder will use these records to
27
/// assemble the correct SQL for each Catalogue in your ExtractionConfiguration.</para>
28
/// 
29
/// <para>The ExtractableColumn 'copy' process allows not only for you to modify the SelectSQL on a 'per extraction' basis but also it means that if you ever delete an ExtractionInformation
30
/// from the Catalogue or change the implementation then the record in DataExport database still reflects the values that were actually used to execute the extraction.  This means
31
/// that if you clone a 10 year old extraction you will still get the same SQL (along with lots of warnings about orphan CatalogueExtractionInformation_ID etc).  It even allows you
32
/// to delete entire datasets (Catalogues) without breaking old extractions (this is not a good idea though - you should always just deprecate the Catalogue instead).</para>
33
/// </summary>
34
public class ExtractableColumn : ConcreteColumn, IComparable, IInjectKnown<CatalogueItem>, IInjectKnown<ColumnInfo>,
35
    IInjectKnown<ExtractionInformation>
36
{
37
    #region Database Properties
38

39
    private int _extractableDataSet_ID;
40
    private int _extractionConfiguration_ID;
41
    private int? _catalogueExtractionInformation_ID;
42

43
    /// <summary>
44
    /// The dataset to which this column belongs.  This is used with <see cref="ExtractionConfiguration_ID"/> to specify which dataset in which extraction
45
    /// this line of SELECT sql is used.
46
    /// </summary>
47
    public int ExtractableDataSet_ID
48
    {
49
        get => _extractableDataSet_ID;
6,766✔
50
        set => SetField(ref _extractableDataSet_ID, value);
6,330✔
51
    }
52

53
    /// <summary>
54
    /// The configuration to which this column belongs.  This is used with <see cref="ExtractableDataSet_ID"/> to specify which dataset in which extraction
55
    /// this line of SELECT sql is used.
56
    /// </summary>
57
    public int ExtractionConfiguration_ID
58
    {
59
        get => _extractionConfiguration_ID;
2,870✔
60
        set => SetField(ref _extractionConfiguration_ID, value);
6,348✔
61
    }
62

63
    /// <summary>
64
    /// The original master column definition this object was cloned from.  When you add a dataset to an <see cref="ExtractionConfiguration"/> all the column
65
    /// definitions are copied to ensure the configuration is preserved going forwards.  This enables old extractions to be rerun regardless of changes in
66
    /// the original dataset.
67
    /// 
68
    /// <para>May be null if the parent catalogue <see cref="ExtractionInformation"/> has been deleted</para>
69
    /// </summary>
70
    public int? CatalogueExtractionInformation_ID
71
    {
72
        get => _catalogueExtractionInformation_ID;
5,714✔
73
        set
74
        {
75
            SetField(ref _catalogueExtractionInformation_ID, value);
6,330✔
76
            ClearAllInjections();
6,330✔
77
        }
6,330✔
78
    }
79

80
    #endregion
81

82
    #region Relationships
83

84
    /// <inheritdoc cref="CatalogueExtractionInformation_ID"/>
85
    [NoMappingToDatabase]
86
    [CanBeNull]
87
    public ExtractionInformation CatalogueExtractionInformation => _knownExtractionInformation.Value;
1,260✔
88

89
    /// <inheritdoc/>
90
    [CanBeNull]
91
    [NoMappingToDatabase]
92
    public override ColumnInfo ColumnInfo => _knownColumnInfo.Value;
5,506✔
93

94
    #endregion
95

96
    public ExtractableColumn()
×
97
    {
98
        ClearAllInjections();
×
99
    }
×
100

101
    /// <summary>
102
    /// Creates a new line of SELECT Sql for the given <paramref name="dataset"/> as it is extracted in the provided <paramref name="configuration"/>.  The new object will
103
    /// be created in the <paramref name="repository"/> database.
104
    /// </summary>
105
    /// <param name="repository"></param>
106
    /// <param name="dataset"></param>
107
    /// <param name="configuration"></param>
108
    /// <param name="extractionInformation"></param>
109
    /// <param name="order"></param>
110
    /// <param name="selectSQL"></param>
111
    public ExtractableColumn(IDataExportRepository repository, IExtractableDataSet dataset,
860✔
112
        ExtractionConfiguration configuration, ExtractionInformation extractionInformation, int order, string selectSQL)
860✔
113
    {
114
        Repository = repository;
860✔
115
        Repository.InsertAndHydrate(this, new Dictionary<string, object>
860!
116
        {
860✔
117
            { "ExtractableDataSet_ID", dataset.ID },
860✔
118
            { "ExtractionConfiguration_ID", configuration.ID },
860✔
119
            {
860✔
120
                "CatalogueExtractionInformation_ID",
860✔
121
                extractionInformation == null ? DBNull.Value : (object)extractionInformation.ID
860✔
122
            },
860✔
123
            { "Order", order },
860✔
124
            { "SelectSQL", string.IsNullOrWhiteSpace(selectSQL) ? DBNull.Value : (object)selectSQL }
860✔
125
        });
860✔
126

127
        ClearAllInjections();
860✔
128
    }
860✔
129

130
    internal ExtractableColumn(IDataExportRepository repository, DbDataReader r)
131
        : base(repository, r)
5,452✔
132
    {
133
        ExtractableDataSet_ID = int.Parse(r["ExtractableDataSet_ID"].ToString());
5,452✔
134
        ExtractionConfiguration_ID = int.Parse(r["ExtractionConfiguration_ID"].ToString());
5,452✔
135

136
        if (r["CatalogueExtractionInformation_ID"] == DBNull.Value)
5,452✔
137
            CatalogueExtractionInformation_ID = null;
4✔
138
        else
139
            CatalogueExtractionInformation_ID = int.Parse(r["CatalogueExtractionInformation_ID"].ToString());
5,448✔
140

141
        SelectSQL = r["SelectSQL"] as string;
5,452✔
142
        Order = int.Parse(r["Order"].ToString());
5,452✔
143
        Alias = r["Alias"] as string;
5,452✔
144
        HashOnDataRelease = (bool)r["HashOnDataRelease"];
5,452✔
145
        IsExtractionIdentifier = (bool)r["IsExtractionIdentifier"];
5,452✔
146
        IsPrimaryKey = (bool)r["IsPrimaryKey"];
5,452✔
147

148
        ClearAllInjections();
5,452✔
149
    }
5,452✔
150

151
    #region value caching and injection
152

153
    private Lazy<CatalogueItem> _knownCatalogueItem;
154
    private Lazy<ColumnInfo> _knownColumnInfo;
155
    private Lazy<ExtractionInformation> _knownExtractionInformation;
156

157
    /// <inheritdoc/>
158
    public void InjectKnown(CatalogueItem instance)
159
    {
160
        _knownCatalogueItem = new Lazy<CatalogueItem>(instance);
48✔
161
    }
48✔
162

163
    /// <inheritdoc/>
164
    public void InjectKnown(ColumnInfo instance)
165
    {
166
        _knownColumnInfo = new Lazy<ColumnInfo>(instance);
48✔
167
    }
48✔
168

169
    /// <inheritdoc/>
170
    public void InjectKnown(ExtractionInformation extractionInformation)
171
    {
172
        if (extractionInformation == null)
24!
173
        {
174
            InjectKnown((CatalogueItem)null);
×
175
            InjectKnown((ColumnInfo)null);
×
176
        }
177
        else
178
        {
179
            InjectKnown(extractionInformation.CatalogueItem);
24✔
180
            InjectKnown(extractionInformation.ColumnInfo);
24✔
181
        }
182

183
        _knownExtractionInformation = new Lazy<ExtractionInformation>(extractionInformation);
24✔
184
    }
24✔
185

186
    /// <inheritdoc/>
187
    public void ClearAllInjections()
188
    {
189
        _knownCatalogueItem = new Lazy<CatalogueItem>(FetchCatalogueItem);
12,642✔
190
        _knownExtractionInformation = new Lazy<ExtractionInformation>(FetchExtractionInformation);
12,642✔
191
        _knownColumnInfo = new Lazy<ColumnInfo>(FetchColumnInfo);
12,642✔
192
    }
12,642✔
193

194
    #endregion
195

196
    /// <summary>
197
    /// Returns the <see cref="ConcreteColumn.SelectSQL"/> or <see cref="ConcreteColumn.Alias"/> of the column (if it has one)
198
    /// </summary>
199
    /// <returns></returns>
200
    public override string ToString() => !string.IsNullOrWhiteSpace(Alias) ? Alias : SelectSQL;
40!
201

202
    /// <summary>
203
    /// Returns true if the underlying column (<see cref="Curation.Data.ColumnInfo"/>) referenced by this class has disapeared since its creation.
204
    /// </summary>
205
    /// <returns></returns>
206
    public bool HasOriginalExtractionInformationVanished() => ColumnInfo == null;
650✔
207

208
    private ColumnInfo FetchColumnInfo()
209
    {
210
        var ci = _knownCatalogueItem.Value;
1,076✔
211
        return ci?.ColumnInfo_ID == null ? null : ci.ColumnInfo;
1,076✔
212
    }
213

214
    private CatalogueItem FetchCatalogueItem()
215
    {
216
        var ei = _knownExtractionInformation.Value;
1,076✔
217

218
        return ei?.CatalogueItem;
1,076✔
219
    }
220

221
    private ExtractionInformation FetchExtractionInformation()
222
    {
223
        //it's not based on a Catalogue column
224
        if (!CatalogueExtractionInformation_ID.HasValue)
1,420!
225
            return null;
×
226

227
        try
228
        {
229
            return ((IDataExportRepository)Repository).CatalogueRepository.GetObjectByID<ExtractionInformation>(
1,420✔
230
                CatalogueExtractionInformation_ID.Value);
1,420✔
231
        }
232
        catch (KeyNotFoundException)
6✔
233
        {
234
            return null;
6✔
235
        }
236
    }
1,420✔
237

238
    /// <summary>
239
    /// Returns true if the current state of the ExtractableColumn is different from the current state of the original <see cref="ExtractionInformation"/> that
240
    /// it was cloned from.
241
    /// </summary>
242
    /// <returns></returns>
243
    public bool IsOutOfSync()
244
    {
245
        var ei = CatalogueExtractionInformation;
48✔
246

247
        if (ei != null)
48✔
248
            if (ei.IsExtractionIdentifier != IsExtractionIdentifier ||
48✔
249
                IsPrimaryKey != ei.IsPrimaryKey ||
48✔
250
                ei.SelectSQL != SelectSQL ||
48✔
251
                ei.Order != Order ||
48✔
252
                ei.Alias != Alias ||
48✔
253
                ei.HashOnDataRelease != HashOnDataRelease)
48✔
254
                return true;
4✔
255

256
        return false;
44✔
257
    }
258

259
    /// <summary>
260
    /// Copies all values (SelectSQL, Order, IsPrimaryKey etc from the specified <see cref="IColumn"/>) then saves to database.
261
    /// </summary>
262
    /// <param name="item"></param>
263
    public void UpdateValuesToMatch(IColumn item)
264
    {
265
        //Add new things you want to copy from the Catalogue here
266
        HashOnDataRelease = item.HashOnDataRelease;
366✔
267
        IsExtractionIdentifier = item.IsExtractionIdentifier;
366✔
268
        IsPrimaryKey = item.IsPrimaryKey;
366✔
269
        Order = item.Order;
366✔
270
        Alias = item.Alias;
366✔
271
        SelectSQL = item.SelectSQL;
366✔
272
        SaveToDatabase();
366✔
273
    }
366✔
274

275
    public ExtractableColumn ShallowClone()
276
    {
277
        var eds = DataExportRepository.GetObjectByID<ExtractableDataSet>(ExtractableDataSet_ID);
18✔
278
        var config = DataExportRepository.GetObjectByID<ExtractionConfiguration>(ExtractionConfiguration_ID);
18✔
279

280
        var clone = new ExtractableColumn(DataExportRepository, eds, config, CatalogueExtractionInformation, Order,
18✔
281
            SelectSQL);
18✔
282
        CopyShallowValuesTo(clone);
18✔
283
        return clone;
18✔
284
    }
285
}
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