Skip to content

Commit

Permalink
Merge pull request #474 from sanger/sample_risk
Browse files Browse the repository at this point in the history
x1247 Sample risk
  • Loading branch information
khelwood authored Nov 20, 2024
2 parents 85e4ca1 + 0aeac3b commit 25e8e17
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ public class OriginalSampleData {
private String species;
private LocalDate sampleCollectionDate;
private String workNumber;
private String bioRiskCode;

public OriginalSampleData() {}

public OriginalSampleData(String donorIdentifier, LifeStage lifeStage, String hmdmc, String tissueType,
Integer spatialLocation, String replicateNumber, String externalIdentifier,
String labwareType, String solution, String fixative, String species,
LocalDate sampleCollectionDate, String workNumber) {
LocalDate sampleCollectionDate, String workNumber, String bioRiskCode) {
this.donorIdentifier = donorIdentifier;
this.lifeStage = lifeStage;
this.hmdmc = hmdmc;
Expand All @@ -44,6 +45,7 @@ public OriginalSampleData(String donorIdentifier, LifeStage lifeStage, String hm
this.species = species;
this.sampleCollectionDate = sampleCollectionDate;
this.workNumber = workNumber;
this.bioRiskCode = bioRiskCode;
}

/**
Expand Down Expand Up @@ -186,6 +188,14 @@ public void setWorkNumber(String workNumber) {
this.workNumber = workNumber;
}

public String getBioRiskCode() {
return this.bioRiskCode;
}

public void setBioRiskCode(String bioRiskCode) {
this.bioRiskCode = bioRiskCode;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -204,6 +214,7 @@ public boolean equals(Object o) {
&& Objects.equals(this.species, that.species)
&& Objects.equals(this.sampleCollectionDate, that.sampleCollectionDate)
&& Objects.equals(this.workNumber, that.workNumber)
&& Objects.equals(this.bioRiskCode, that.bioRiskCode)
);
}

Expand All @@ -229,6 +240,7 @@ public String toString() {
.add("species", species)
.add("sampleCollectionDate", sampleCollectionDate)
.add("workNumber", workNumber)
.add("bioRiskCode", bioRiskCode)
.reprStringValues()
.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class OriginalSampleRegisterServiceImp implements IRegisterService<Origin
private final LabwareService labwareService;
private final OperationService opService;
private final WorkService workService;
private final BioRiskService bioRiskService;

@Autowired
public OriginalSampleRegisterServiceImp(DonorRepo donorRepo, TissueRepo tissueRepo,
Expand All @@ -62,7 +63,7 @@ public OriginalSampleRegisterServiceImp(DonorRepo donorRepo, TissueRepo tissueRe
@Qualifier("hmdmcValidator") Validator<String> hmdmcValidator,
@Qualifier("replicateValidator") Validator<String> replicateValidator,
LabwareService labwareService, OperationService opService,
WorkService workService) {
WorkService workService, BioRiskService bioRiskService) {
this.donorRepo = donorRepo;
this.tissueRepo = tissueRepo;
this.tissueTypeRepo = tissueTypeRepo;
Expand All @@ -84,6 +85,7 @@ public OriginalSampleRegisterServiceImp(DonorRepo donorRepo, TissueRepo tissueRe
this.labwareService = labwareService;
this.opService = opService;
this.workService = workService;
this.bioRiskService = bioRiskService;
}

@Override
Expand Down Expand Up @@ -123,6 +125,7 @@ public RegisterResult register(User user, OriginalSampleRegisterRequest request)
checkExternalNamesUnique(problems, request);
checkDonorFieldsAreConsistent(problems, datas);
checkTissueTypesAndSpatialLocations(problems, datas);
checkBioRisks(problems, datas);

if (!problems.isEmpty()) {
throw new ValidationException("The request validation failed.", problems);
Expand All @@ -134,6 +137,7 @@ public RegisterResult register(User user, OriginalSampleRegisterRequest request)
recordRegistrations(user, datas);
recordSolutions(datas);
linkWork(datas);
linkBioRisks(datas);
return makeResult(datas);
}

Expand Down Expand Up @@ -397,6 +401,21 @@ void checkWorks(Collection<String> problems, List<DataStruct> datas) {
}
}

/**
* Checks bio risk codes are specified and correspond to known bio risks
* @param problems receptacle for problems
* @param datas data in progress
*/
void checkBioRisks(Collection<String> problems, List<DataStruct> datas) {
UCMap<BioRisk> riskMap = bioRiskService.loadAndValidateBioRisks(problems, datas.stream().map(DataStruct::getOriginalSampleData),
OriginalSampleData::getBioRiskCode, OriginalSampleData::setBioRiskCode);
if (!riskMap.isEmpty()) {
for (DataStruct data : datas) {
data.setBioRisk(riskMap.get(data.originalSampleData.getBioRiskCode()));
}
}
}

/**
* Loads any existing donors matching given donor names.
* The donors are placed in the appropriate field in the DataStructs.
Expand Down Expand Up @@ -493,6 +512,16 @@ void linkWork(List<DataStruct> datas) {
workService.linkWorkOps(workOps);
}

/**
* Link samples and operations to the indicated bio risk
* @param datas created data
*/
void linkBioRisks(List<DataStruct> datas) {
for (DataStruct data : datas) {
bioRiskService.recordSampleBioRisks(Map.of(data.sample.getId(), data.bioRisk), data.operation.getId());
}
}

/**
* Creates labware for each data element
* @param datas the data under construction
Expand Down Expand Up @@ -548,6 +577,7 @@ static class DataStruct {
Fixative fixative;
Species species;
Work work;
BioRisk bioRisk;

Donor donor;
Sample sample;
Expand Down Expand Up @@ -585,5 +615,9 @@ void setSpecies(Species species) {
public void setWork(Work work) {
this.work = work;
}

void setBioRisk(BioRisk risk) {
this.bioRisk = risk;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum Column implements IColumn {
Life_stage,
Collection_date(LocalDate.class, Pattern.compile("(if.*)?(date.*collection|collection.*date).*", Pattern.CASE_INSENSITIVE), false),
Species,
Bio_risk(Pattern.compile("bio\\w*\\s+risk.*", Pattern.CASE_INSENSITIVE)),
HuMFre(Pattern.compile("humfre\\s*(number)?", Pattern.CASE_INSENSITIVE), false),
Tissue_type,
External_identifier(Pattern.compile("external\\s*id.*", Pattern.CASE_INSENSITIVE), false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public OriginalSampleData createSampleData(Collection<String> problems, Map<Colu
data.setLifeStage(valueToLifeStage(problems, (String) row.get(Column.Life_stage)));
data.setSampleCollectionDate((LocalDate) row.get(Column.Collection_date));
data.setSpecies((String) row.get(Column.Species));
data.setBioRiskCode((String) row.get(Column.Bio_risk));
data.setHmdmc((String) row.get(Column.HuMFre));
data.setTissueType((String) row.get(Column.Tissue_type));
data.setExternalIdentifier((String) row.get(Column.External_identifier));
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ input OriginalSampleData {
sampleCollectionDate: Date
"""The optional work number to link to the registration."""
workNumber: String
"""The biological risk number for this sample."""
bioRiskCode: String!
}

"""A request to register one or more original samples of tissue."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public class TestRegisterOriginalSamplesMutation {
private OperationRepo opRepo;
@Autowired
private OperationSolutionRepo opSolRepo;
@Autowired
private BioRiskRepo bioRiskRepo;
@MockBean
private StorelightClient mockStorelight;

Expand All @@ -55,6 +57,7 @@ public void testRegisterOriginalSamples(boolean hasExternalName) throws Exceptio
stubStorelightUnstore(mockStorelight);

User user = entityCreator.createUser("user1");
BioRisk risk1 = entityCreator.createBioRisk("risk1");
tester.setUser(user);
Solution solution = solutionRepo.save(new Solution(null, "Glue"));
String externalName = (hasExternalName ? "EXT1" : null);
Expand Down Expand Up @@ -105,6 +108,7 @@ public void testRegisterOriginalSamples(boolean hasExternalName) throws Exceptio
Map<String, String> lwSol = lwSolData.get(0);
assertEquals(lw.getBarcode(), lwSol.get("barcode"));
assertEquals(solution.getName(), lwSol.get("solutionName"));
assertThat(bioRiskRepo.loadBioRiskForSampleId(sample.getId())).contains(risk1);

Work work = entityCreator.createWork(null, null, null, null, null);
Labware block = testBlockProcessing(barcode, work);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public class TestOriginalSampleRegisterService {
private OperationService mockOpService;
@Mock
private WorkService mockWorkService;
@Mock
private BioRiskService mockBioRiskService;

OriginalSampleRegisterServiceImp service;

Expand All @@ -87,7 +89,8 @@ void setup() {
mockSampleRepo, mockBsRepo, mockSlotRepo, mockHmdmcRepo, mockSpeciesRepo, mockFixativeRepo,
mockMediumRepo, mockSolutionRepo, mockLtRepo, mockOpTypeRepo, mockOpSolRepo, mockDonorNameValidator,
mockExternalNameValidator,
mockHmdmcValidator, mockReplicateValidator, mockLabwareService, mockOpService, mockWorkService));
mockHmdmcValidator, mockReplicateValidator, mockLabwareService, mockOpService, mockWorkService,
mockBioRiskService));
}

@AfterEach
Expand All @@ -111,7 +114,7 @@ public void testRegister_noSamples() {
@Test
public void testRegister_validationErrors() {
OriginalSampleData data = new OriginalSampleData("DONOR1", LifeStage.adult, "HMDMC1", "TISSUE1", 5,
"R1", "EXT1", "LT1", "SOL1", "FIX1", "SPEC1", LocalDate.of(2022,1,1), "TODO");
"R1", "EXT1", "LT1", "SOL1", "FIX1", "SPEC1", LocalDate.of(2022,1,1), "TODO", "RISK1");
OriginalSampleRegisterRequest request = new OriginalSampleRegisterRequest(List.of(data));

doAnswer(invocation -> {
Expand All @@ -134,6 +137,7 @@ public void testRegister_validationErrors() {

doNothing().when(service).checkExternalNamesUnique(any(), any());
doNothing().when(service).checkDonorFieldsAreConsistent(any(), any());
doNothing().when(service).checkBioRisks(any(), any());

User user = EntityFactory.getUser();

Expand Down Expand Up @@ -165,11 +169,12 @@ public void testRegister_validationErrors() {
public void testRegister_valid() {
User user = EntityFactory.getUser();
OriginalSampleData data = new OriginalSampleData("DONOR1", LifeStage.adult, "HMDMC1", "TISSUE1", 5,
"R1", "EXT1", "LT1", "SOL1", "FIX1", "SPEC1", LocalDate.of(2022,1,1), "TODO");
"R1", "EXT1", "LT1", "SOL1", "FIX1", "SPEC1", LocalDate.of(2022,1,1), "TODO", "risk1");
OriginalSampleRegisterRequest request = new OriginalSampleRegisterRequest(List.of(data));
doNothing().when(service).checkFormat(any(), any(), any(), any(), anyBoolean(), any());
doNothing().when(service).checkHmdmcsForSpecies(any(), any());
doNothing().when(service).checkCollectionDates(any(), any());
doNothing().when(service).checkBioRisks(any(), any());

doNothing().when(service).checkExistence(any(), any(), any(), any(), any(), any());

Expand All @@ -184,6 +189,7 @@ public void testRegister_valid() {
doNothing().when(service).createNewLabware(any());
doNothing().when(service).recordRegistrations(any(), any());
doNothing().when(service).recordSolutions(any());
doNothing().when(service).linkBioRisks(any());
final RegisterResult expectedResult = new RegisterResult(List.of(EntityFactory.getTube()));
doReturn(expectedResult).when(service).makeResult(any());

Expand All @@ -196,6 +202,7 @@ public void testRegister_valid() {
verify(service).recordRegistrations(same(user), same(datas));
verify(service).recordSolutions(same(datas));
verify(service).linkWork(same(datas));
verify(service).linkBioRisks(same(datas));
verify(service).makeResult(same(datas));
}

Expand Down Expand Up @@ -229,6 +236,7 @@ private List<DataStruct> verifyValidationMethods(OriginalSampleRegisterRequest r
verify(service).checkDonorFieldsAreConsistent(same(problems), same(datas));

verify(service).checkTissueTypesAndSpatialLocations(same(problems), same(datas));
verify(service).checkBioRisks(same(problems), same(datas));
return datas;
}

Expand Down Expand Up @@ -607,6 +615,36 @@ public void testCheckWorks_ok(boolean errors) {
verify(mockWorkService).validateUsableWorks(any(), eq(Set.of("SGP1", "SGP2")));
}

@SuppressWarnings("unchecked")
@Test
public void testCheckBioRisks() {
BioRisk risk1 = new BioRisk(1, "risk1");
BioRisk risk2 = new BioRisk(2, "risk2");
UCMap<BioRisk> riskMap = UCMap.from(BioRisk::getCode, risk1, risk2);
List<DataStruct> datas = Stream.of("RISK1","", "risk2")
.map(code -> {
OriginalSampleData osd = new OriginalSampleData();
osd.setBioRiskCode(code);
return new DataStruct(osd);
})
.toList();
when(mockBioRiskService.loadAndValidateBioRisks(any(), any(), any(), any())).thenReturn(riskMap);

ArgumentCaptor<Function<OriginalSampleData, String>> getterCaptor = ArgumentCaptor.forClass(Function.class);
ArgumentCaptor<BiConsumer<OriginalSampleData, String>> setterCaptor = ArgumentCaptor.forClass(BiConsumer.class);
ArgumentCaptor<Stream<OriginalSampleData>> streamCaptor = ArgumentCaptor.forClass(Stream.class);
final List<String> problems = new ArrayList<>();
service.checkBioRisks(problems, datas);
verify(mockBioRiskService).loadAndValidateBioRisks(same(problems), streamCaptor.capture(), getterCaptor.capture(), setterCaptor.capture());
// Test the correct stream and getter were passed
assertThat(streamCaptor.getValue().map(getterCaptor.getValue())).containsExactly("RISK1","", "risk2");
OriginalSampleData osd = new OriginalSampleData();
// Test the correct setter was passed
setterCaptor.getValue().accept(osd, "Banana");
assertEquals("Banana", osd.getBioRiskCode());
assertThat(datas.stream().map(data -> data.bioRisk)).containsExactly(risk1, null, risk2);
}

@Test
public void testLoadDonors_none() {
List<DataStruct> datas = Stream.of(osdWithDonor(""), osdWithDonor(null))
Expand Down Expand Up @@ -679,6 +717,37 @@ static DataStruct dataStructOf(String donorName, Donor donor, Species species, L
return data;
}

@Test
public void testLinkBioRisks() {
Operation[] ops = IntStream.range(100,103)
.mapToObj(id -> {
Operation op = new Operation();
op.setId(id);
return op;
}).toArray(Operation[]::new);
Sample[] samples = EntityFactory.makeSamples(ops.length);
BioRisk risk1 = new BioRisk(201, "risk1");
BioRisk risk2 = new BioRisk(202, "risk2");
List<DataStruct> datas = List.of(
dataForRisk(ops[0], samples[0], risk1),
dataForRisk(ops[1], samples[1], risk2),
dataForRisk(ops[2], samples[2], risk1)
);
service.linkBioRisks(datas);
verify(mockBioRiskService, times(datas.size())).recordSampleBioRisks(any(), any());
verify(mockBioRiskService).recordSampleBioRisks(Map.of(samples[0].getId(), risk1), ops[0].getId());
verify(mockBioRiskService).recordSampleBioRisks(Map.of(samples[1].getId(), risk2), ops[1].getId());
verify(mockBioRiskService).recordSampleBioRisks(Map.of(samples[2].getId(), risk1), ops[2].getId());
}

private static DataStruct dataForRisk(Operation op, Sample sample, BioRisk risk) {
DataStruct data = new DataStruct(null);
data.operation = op;
data.sample = sample;
data.bioRisk = risk;
return data;
}

@Test
public void testCreateNewSamples() {
Species human = EntityFactory.getHuman();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void testColumns() {
void testHeadings() {
OriginalSampleRegisterFileReaderImp reader = spy(new OriginalSampleRegisterFileReaderImp());
String[] headings = {"mandatory whatever", "SGP number", "donor identifier", "life stage",
"if such and such date of collection", "species", "humfre", "tissue type", "external identifier",
"if such and such date of collection", "species", "bio risk", "humfre", "tissue type", "external identifier",
"spatial location", "replicate", "labware type",
"fixative", "solution of things", "information about whatever"};
Row row = mockRow(headings);
Expand All @@ -58,7 +58,7 @@ void testCreateSampleData() {
final LocalDate date = LocalDate.of(2023, 1, 2);
Object[] values = {
"junk", "SGP15", "DONOR1", "fetal", date,
"human", "12345", "tt1", "EXT1", 12, "11A", "bowl", "fix1", "sol1", "junkyjunk"
"human", "risk1", "12345", "tt1", "EXT1", 12, "11A", "bowl", "fix1", "sol1", "junkyjunk"
};
Column[] columns = Column.values();
for (int i = 0; i < values.length; ++i) {
Expand All @@ -74,6 +74,7 @@ void testCreateSampleData() {
assertEquals(LifeStage.fetal, data.getLifeStage());
assertEquals(date, data.getSampleCollectionDate());
assertEquals("human", data.getSpecies());
assertEquals("risk1", data.getBioRiskCode());
assertEquals("12345", data.getHmdmc());
assertEquals("tt1", data.getTissueType());
assertEquals("EXT1", data.getExternalIdentifier());
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/graphql/registeroriginal.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mutation {
donorIdentifier:"DONOR1"
species: "Human"
lifeStage:adult
bioRiskCode: "risk1"
hmdmc:"20/0002"
spatialLocation:0
tissueType:"Bone"
Expand Down

0 comments on commit 25e8e17

Please sign in to comment.