Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Commit 2a9b54d

Browse files
feat: Map empty strings to null for optional fields
1 parent f4c3aba commit 2a9b54d

2 files changed

Lines changed: 77 additions & 40 deletions

File tree

src/ServiceLayer.Mesh/FileTypes/NbssAppointmentEvents/StagingPersister.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,18 @@ private static List<NbssAppointmentEvent> MapFileDataRecordsToNbssAppointmentEve
2525
Sequence = record.Fields["Sequence"],
2626
Action = record.Fields["Action"],
2727
ClinicCode = record.Fields["Clinic Code"],
28-
HoldingClinic = record.Fields["Holding Clinic"],
28+
HoldingClinic = NullIfWhiteSpace(record.Fields["Holding Clinic"]),
2929
Status = record.Fields["Status"],
30-
AttendedNotScreened = record.Fields["Attended Not Scr"],
30+
AttendedNotScreened = NullIfWhiteSpace(record.Fields["Attended Not Scr"]),
3131
AppointmenId = record.Fields["Appointment ID"],
3232
NhsNumber = record.Fields["NHS Num"],
3333
EpisodeType = record.Fields["Episode Type"],
3434
EpisodeStart = DateOnly.ParseExact(record.Fields["Episode Start"], "yyyyMMdd", CultureInfo.InvariantCulture),
3535
BatchId = record.Fields["Batch ID"],
3636
AppointmentType = record.Fields["Screen or Asses"],
37-
ScreeningAppointmentNumber = byte.Parse(record.Fields["Screen Appt num"]),
37+
ScreeningAppointmentNumber = NullByteIfWhiteSpace(record.Fields["Screen Appt num"]),
3838
BookedBy = record.Fields["Booked By"],
39-
CancelledBy = record.Fields["Cancelled By"],
39+
CancelledBy = NullIfWhiteSpace(record.Fields["Cancelled By"]),
4040
AppointmentDateTime = DateTime.ParseExact(record.Fields["Appt Date"] + record.Fields["Appt Time"], "yyyyMMddHHmm", CultureInfo.InvariantCulture),
4141
Location = record.Fields["Location"],
4242
ClinicName = record.Fields["Clinic Name"],
@@ -50,4 +50,8 @@ private static List<NbssAppointmentEvent> MapFileDataRecordsToNbssAppointmentEve
5050
ActionTimestamp = DateTime.ParseExact(record.Fields["Action Timestamp"], "yyyyMMdd-HHmmss", CultureInfo.InvariantCulture)
5151
})];
5252
}
53+
54+
private static string? NullIfWhiteSpace(string input) => string.IsNullOrWhiteSpace(input) ? null : input;
55+
56+
private static byte? NullByteIfWhiteSpace(string input) => string.IsNullOrWhiteSpace(input) ? null : byte.Parse(input);
5357
}

tests/ServiceLayer.Mesh.Tests/FileTypes/NbssAppointmentEvents/StagingPersisterTests.cs

Lines changed: 69 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@ public NbssAppointmentEventsTests()
2222
}
2323

2424
[Fact]
25-
public async Task WriteStagedData_WhenFileValid_SavesToDb()
25+
public async Task WriteStagedData_WhenFileValid_MapsFieldsAndSavesToDb()
2626
{
2727
// Arrange
28-
var parsedFile = TestDataBuilder.BuildValidParsedFile();
28+
var parsedFile = TestDataBuilder.BuildValidParsedFile(3);
29+
var firstRecord = parsedFile.DataRecords[0];
30+
firstRecord.Fields["Attended Not Scr"] = "Y";
31+
firstRecord.Fields["Cancelled By"] = "C";
2932
var meshFile = new MeshFile()
3033
{
3134
FileId = "1",
@@ -41,37 +44,66 @@ public async Task WriteStagedData_WhenFileValid_SavesToDb()
4144
Assert.Equal(3, await _dbContext.NbssAppointmentEvents.CountAsync());
4245

4346
var nbssAppointmentEvent = await _dbContext.NbssAppointmentEvents.FirstAsync();
44-
var dataRecord = parsedFile.DataRecords.First();
4547
Assert.NotEqual(Guid.Empty, nbssAppointmentEvent.Id);
4648
Assert.Equal(meshFile.FileId, nbssAppointmentEvent.MeshFileId);
47-
Assert.Equal(dataRecord["BSO"], nbssAppointmentEvent.BSO);
49+
Assert.Equal(firstRecord["BSO"], nbssAppointmentEvent.BSO);
4850
Assert.Equal(parsedFile.FileTrailer!.ExtractId, nbssAppointmentEvent.ExtractId);
49-
Assert.Equal(dataRecord["Sequence"], nbssAppointmentEvent.Sequence);
50-
Assert.Equal(dataRecord["Action"], nbssAppointmentEvent.Action);
51-
Assert.Equal(dataRecord["Clinic Code"], nbssAppointmentEvent.ClinicCode);
52-
Assert.Equal(dataRecord["Holding Clinic"], nbssAppointmentEvent.HoldingClinic);
53-
Assert.Equal(dataRecord["Status"], nbssAppointmentEvent.Status);
54-
Assert.Equal(dataRecord["Attended Not Scr"], nbssAppointmentEvent.AttendedNotScreened);
55-
Assert.Equal(dataRecord["Appointment ID"], nbssAppointmentEvent.AppointmenId);
56-
Assert.Equal(dataRecord["NHS Num"], nbssAppointmentEvent.NhsNumber);
57-
Assert.Equal(dataRecord["Episode Type"], nbssAppointmentEvent.EpisodeType);
58-
Assert.Equal(DateOnly.ParseExact(dataRecord.Fields["Episode Start"], "yyyyMMdd"), nbssAppointmentEvent.EpisodeStart);
59-
Assert.Equal(dataRecord["Batch ID"], nbssAppointmentEvent.BatchId);
60-
Assert.Equal(dataRecord["Screen or Asses"], nbssAppointmentEvent.AppointmentType);
61-
Assert.Equal(byte.Parse(dataRecord.Fields["Screen Appt num"]), nbssAppointmentEvent.ScreeningAppointmentNumber);
62-
Assert.Equal(dataRecord["Booked By"], nbssAppointmentEvent.BookedBy);
63-
Assert.Equal(dataRecord["Cancelled By"], nbssAppointmentEvent.CancelledBy);
64-
Assert.Equal(DateTime.ParseExact(dataRecord.Fields["Appt Date"] + dataRecord.Fields["Appt Time"], "yyyyMMddHHmm", null), nbssAppointmentEvent.AppointmentDateTime);
65-
Assert.Equal(dataRecord["Location"], nbssAppointmentEvent.Location);
66-
Assert.Equal(dataRecord["Clinic Name"], nbssAppointmentEvent.ClinicName);
67-
Assert.Equal(dataRecord["Clinic Name (Let)"], nbssAppointmentEvent.ClinicNameOnLetters);
68-
Assert.Equal(dataRecord["Clinic Address 1"], nbssAppointmentEvent.ClinicAddressLine1);
69-
Assert.Equal(dataRecord["Clinic Address 2"], nbssAppointmentEvent.ClinicAddressLine2);
70-
Assert.Equal(dataRecord["Clinic Address 3"], nbssAppointmentEvent.ClinicAddressLine3);
71-
Assert.Equal(dataRecord["Clinic Address 4"], nbssAppointmentEvent.ClinicAddressLine4);
72-
Assert.Equal(dataRecord["Clinic Address 5"], nbssAppointmentEvent.ClinicAddressLine5);
73-
Assert.Equal(dataRecord["Postcode"], nbssAppointmentEvent.ClinicPostcode);
74-
Assert.Equal(DateTime.ParseExact(dataRecord.Fields["Action Timestamp"], "yyyyMMdd-HHmmss", null), nbssAppointmentEvent.ActionTimestamp);
51+
Assert.Equal(firstRecord["Sequence"], nbssAppointmentEvent.Sequence);
52+
Assert.Equal(firstRecord["Action"], nbssAppointmentEvent.Action);
53+
Assert.Equal(firstRecord["Clinic Code"], nbssAppointmentEvent.ClinicCode);
54+
Assert.Equal(firstRecord["Holding Clinic"], nbssAppointmentEvent.HoldingClinic);
55+
Assert.Equal(firstRecord["Status"], nbssAppointmentEvent.Status);
56+
Assert.Equal(firstRecord["Attended Not Scr"], nbssAppointmentEvent.AttendedNotScreened);
57+
Assert.Equal(firstRecord["Appointment ID"], nbssAppointmentEvent.AppointmenId);
58+
Assert.Equal(firstRecord["NHS Num"], nbssAppointmentEvent.NhsNumber);
59+
Assert.Equal(firstRecord["Episode Type"], nbssAppointmentEvent.EpisodeType);
60+
Assert.Equal(DateOnly.ParseExact(firstRecord.Fields["Episode Start"], "yyyyMMdd"), nbssAppointmentEvent.EpisodeStart);
61+
Assert.Equal(firstRecord["Batch ID"], nbssAppointmentEvent.BatchId);
62+
Assert.Equal(firstRecord["Screen or Asses"], nbssAppointmentEvent.AppointmentType);
63+
Assert.Equal(byte.Parse(firstRecord.Fields["Screen Appt num"]), nbssAppointmentEvent.ScreeningAppointmentNumber);
64+
Assert.Equal(firstRecord["Booked By"], nbssAppointmentEvent.BookedBy);
65+
Assert.Equal(firstRecord["Cancelled By"], nbssAppointmentEvent.CancelledBy);
66+
Assert.Equal(DateTime.ParseExact(firstRecord.Fields["Appt Date"] + firstRecord.Fields["Appt Time"], "yyyyMMddHHmm", null), nbssAppointmentEvent.AppointmentDateTime);
67+
Assert.Equal(firstRecord["Location"], nbssAppointmentEvent.Location);
68+
Assert.Equal(firstRecord["Clinic Name"], nbssAppointmentEvent.ClinicName);
69+
Assert.Equal(firstRecord["Clinic Name (Let)"], nbssAppointmentEvent.ClinicNameOnLetters);
70+
Assert.Equal(firstRecord["Clinic Address 1"], nbssAppointmentEvent.ClinicAddressLine1);
71+
Assert.Equal(firstRecord["Clinic Address 2"], nbssAppointmentEvent.ClinicAddressLine2);
72+
Assert.Equal(firstRecord["Clinic Address 3"], nbssAppointmentEvent.ClinicAddressLine3);
73+
Assert.Equal(firstRecord["Clinic Address 4"], nbssAppointmentEvent.ClinicAddressLine4);
74+
Assert.Equal(firstRecord["Clinic Address 5"], nbssAppointmentEvent.ClinicAddressLine5);
75+
Assert.Equal(firstRecord["Postcode"], nbssAppointmentEvent.ClinicPostcode);
76+
Assert.Equal(DateTime.ParseExact(firstRecord.Fields["Action Timestamp"], "yyyyMMdd-HHmmss", null), nbssAppointmentEvent.ActionTimestamp);
77+
}
78+
79+
[Fact]
80+
public async Task WriteStagedData_WhenOptionalFieldsAreEmpty_MapsFieldToNullAndSavesToDb()
81+
{
82+
// Arrange
83+
var parsedFile = TestDataBuilder.BuildValidParsedFile(1);
84+
parsedFile.DataRecords[0].Fields["Holding Clinic"] = "";
85+
parsedFile.DataRecords[0].Fields["Attended Not Scr"] = "";
86+
parsedFile.DataRecords[0].Fields["Screen Appt num"] = "";
87+
parsedFile.DataRecords[0].Fields["Cancelled By"] = "";
88+
var meshFile = new MeshFile()
89+
{
90+
FileId = "1",
91+
FileType = MeshFileType.NbssAppointmentEvents,
92+
MailboxId = "ABC",
93+
Status = MeshFileStatus.Transforming
94+
};
95+
96+
// Act
97+
await _stagingPersister.WriteStagedData(parsedFile, meshFile);
98+
99+
// Assert
100+
Assert.Equal(1, await _dbContext.NbssAppointmentEvents.CountAsync());
101+
102+
var nbssAppointmentEvent = await _dbContext.NbssAppointmentEvents.FirstAsync();
103+
Assert.Null(nbssAppointmentEvent.HoldingClinic);
104+
Assert.Null(nbssAppointmentEvent.AttendedNotScreened);
105+
Assert.Null(nbssAppointmentEvent.ScreeningAppointmentNumber);
106+
Assert.Null(nbssAppointmentEvent.CancelledBy);
75107
}
76108

77109
[Theory]
@@ -106,9 +138,9 @@ public async Task WriteStagedData_WhenFileValid_SavesToDb()
106138
public async Task WriteStagedData_WhenFieldMissing_DoesNotSaveToDb(string fieldName)
107139
{
108140
// Arrange
109-
var parsedFile = TestDataBuilder.BuildValidParsedFile();
110-
var recordWithoutBSO = TestDataBuilder.BuildFileDataRecordWithField(fieldName, null, 1);
111-
parsedFile.DataRecords.Add(recordWithoutBSO);
141+
var parsedFile = TestDataBuilder.BuildValidParsedFile(0);
142+
var record = TestDataBuilder.BuildFileDataRecordWithField(fieldName, null, 1);
143+
parsedFile.DataRecords.Add(record);
112144
var meshFile = new MeshFile()
113145
{
114146
FileId = "1",
@@ -127,12 +159,13 @@ public async Task WriteStagedData_WhenFieldMissing_DoesNotSaveToDb(string fieldN
127159
[InlineData("Screen Appt num")]
128160
[InlineData("Appt Date")]
129161
[InlineData("Appt Time")]
162+
[InlineData("Action Timestamp")]
130163
public async Task WriteStagedData_WhenFieldHoldsInvalidValue_DoesNotSaveToDb(string fieldName)
131164
{
132165
// Arrange
133-
var parsedFile = TestDataBuilder.BuildValidParsedFile();
134-
var recordWithoutBSO = TestDataBuilder.BuildFileDataRecordWithField(fieldName, "Invalid value", 1);
135-
parsedFile.DataRecords.Add(recordWithoutBSO);
166+
var parsedFile = TestDataBuilder.BuildValidParsedFile(0);
167+
var record = TestDataBuilder.BuildFileDataRecordWithField(fieldName, "Invalid value", 1);
168+
parsedFile.DataRecords.Add(record);
136169
var meshFile = new MeshFile()
137170
{
138171
FileId = "1",

0 commit comments

Comments
 (0)