1
0
mirror of https://github.com/pcvolkmer/mv64e-onkostar-data.git synced 2025-07-02 02:22:54 +00:00

feat: add Tumor-Proben

This commit is contained in:
2025-06-30 00:46:07 +02:00
parent 69af1663e0
commit 60cbb0ff8a
11 changed files with 964 additions and 23 deletions

View File

@ -36,25 +36,25 @@ var jsonResult = Converter.toJsonString(
## Status
| DNPM-Datenmodell 2.1 - Bereich | Status | Anmerkung |
|----------------------------------|--------|----------------------------------------------------------------|
| Patient | ✅ | Verwendet Datenbank-ID, keine managing Site |
| Episoden | ✅ | |
| Diagnosen | ✅ | Entsprechend Formularaufbau nur Diagnose der aktuellen Episode |
| Verwandten-Diagnosen | ✅ | |
| Systemische Leitlinien-Therapien | ✅ | Siehe auch: https://github.com/dnpm-dip/mtb-model/issues/9 |
| Leitlinien-Prozeduren | ✅ | Siehe auch: https://github.com/dnpm-dip/mtb-model/issues/9 |
| ECOG-Verlauf | ✅ | |
| Tumor-Proben | | Aktuell in Arbeit |
| vorherige Molekular-Diagnostik | ⌛ | Aktuell in Arbeit |
| Histologie-Berichte | ⌛ | Aktuell in Arbeit |
| IHC-Berichte | | |
| MSI-Befunde | | |
| NGS-Berichte | ⌛ | Aktuell in Arbeit |
| MTB-Beschlüsse | ⌛ | Aktuell in Arbeit |
| Follow-Up Verlauf | | |
| Antrag Kostenübernahme | | |
| Antwort Kostenübernahme | | |
| Therapien | | |
| Response Befunde | | |
| DNPM-Datenmodell 2.1 - Bereich | Status | Anmerkung |
|----------------------------------|--------|----------------------------------------------------------------------------|
| Patient | ✅ | Verwendet Datenbank-ID, keine managing Site |
| Episoden | ✅ | |
| Diagnosen | ✅ | Entsprechend Formularaufbau nur Diagnose der aktuellen Episode |
| Verwandten-Diagnosen | ✅ | |
| Systemische Leitlinien-Therapien | ✅ | Siehe auch: https://github.com/dnpm-dip/mtb-model/issues/9 |
| Leitlinien-Prozeduren | ✅ | Siehe auch: https://github.com/dnpm-dip/mtb-model/issues/9 |
| ECOG-Verlauf | ✅ | |
| Tumor-Proben | | Best effort: Formular OS.Molekulargenetik erfüllt nicht alle Anforderungen |
| vorherige Molekular-Diagnostik | ⌛ | Aktuell in Arbeit |
| Histologie-Berichte | ⌛ | Aktuell in Arbeit |
| IHC-Berichte | | |
| MSI-Befunde | | |
| NGS-Berichte | ⌛ | Aktuell in Arbeit |
| MTB-Beschlüsse | ⌛ | Aktuell in Arbeit |
| Follow-Up Verlauf | | |
| Antrag Kostenübernahme | | |
| Antwort Kostenübernahme | | |
| Therapien | | |
| Response Befunde | | |

View File

@ -71,6 +71,12 @@ public class DataCatalogueFactory {
return TherapieplanCatalogue.create(jdbcTemplate);
} else if (c == EinzelempfehlungCatalogue.class) {
return EinzelempfehlungCatalogue.create(jdbcTemplate);
} else if (c == MolekulargenetikCatalogue.class) {
return MolekulargenetikCatalogue.create(jdbcTemplate);
} else if (c == RebiopsieCatalogue.class) {
return RebiopsieCatalogue.create(jdbcTemplate);
} else if (c == ReevaluationCatalogue.class) {
return ReevaluationCatalogue.create(jdbcTemplate);
}
throw new DataCatalogueCreationException(clazz);
});

View File

@ -0,0 +1,26 @@
package dev.pcvolkmer.onco.datamapper.datacatalogues;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* Load raw result sets from database table 'dk_molekulargenetik'
*
* @author Paul-Christian Volkmer
* @since 0.1
*/
public class MolekulargenetikCatalogue extends AbstractSubformDataCatalogue {
private MolekulargenetikCatalogue(JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}
@Override
protected String getTableName() {
return "dk_molekulargenetik";
}
public static MolekulargenetikCatalogue create(JdbcTemplate jdbcTemplate) {
return new MolekulargenetikCatalogue(jdbcTemplate);
}
}

View File

@ -0,0 +1,26 @@
package dev.pcvolkmer.onco.datamapper.datacatalogues;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* Load raw result sets from database table 'dk_dnpm_uf_rebiopsie'
*
* @author Paul-Christian Volkmer
* @since 0.1
*/
public class RebiopsieCatalogue extends AbstractSubformDataCatalogue {
private RebiopsieCatalogue(JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}
@Override
protected String getTableName() {
return "dk_dnpm_uf_rebiopsie";
}
public static RebiopsieCatalogue create(JdbcTemplate jdbcTemplate) {
return new RebiopsieCatalogue(jdbcTemplate);
}
}

View File

@ -0,0 +1,26 @@
package dev.pcvolkmer.onco.datamapper.datacatalogues;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* Load raw result sets from database table 'dk_dnpm_uf_reevaluation'
*
* @author Paul-Christian Volkmer
* @since 0.1
*/
public class ReevaluationCatalogue extends AbstractSubformDataCatalogue {
private ReevaluationCatalogue(JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}
@Override
protected String getTableName() {
return "dk_dnpm_uf_reevaluation";
}
public static ReevaluationCatalogue create(JdbcTemplate jdbcTemplate) {
return new ReevaluationCatalogue(jdbcTemplate);
}
}

View File

@ -0,0 +1,215 @@
package dev.pcvolkmer.onco.datamapper.mapper;
import dev.pcvolkmer.mv64e.mtb.*;
import dev.pcvolkmer.onco.datamapper.PropertyCatalogue;
import dev.pcvolkmer.onco.datamapper.ResultSet;
import dev.pcvolkmer.onco.datamapper.datacatalogues.*;
import java.util.List;
import java.util.stream.Collectors;
import static dev.pcvolkmer.onco.datamapper.mapper.MapperUtils.getPatientReference;
/**
* Mapper class to load and map patient data from database table 'dk_molekulargenetik'
*
* @author Paul-Christian Volkmer
* @since 0.1
*/
public class MolekulargenetikToSpecimenDataMapper implements DataMapper<TumorSpecimen> {
private final MolekulargenetikCatalogue molekulargenetikCatalogue;
private final TherapieplanCatalogue therapieplanCatalogue;
private final RebiopsieCatalogue rebiopsieCatalogue;
private final ReevaluationCatalogue reevaluationCatalogue;
private final EinzelempfehlungCatalogue einzelempfehlungCatalogue;
private final PropertyCatalogue propertyCatalogue;
public MolekulargenetikToSpecimenDataMapper(
final MolekulargenetikCatalogue molekulargenetikCatalogue,
final TherapieplanCatalogue therapieplanCatalogue,
final RebiopsieCatalogue rebiopsieCatalogue,
final ReevaluationCatalogue reevaluationCatalogue,
final EinzelempfehlungCatalogue einzelempfehlungCatalogue,
final PropertyCatalogue propertyCatalogue
) {
this.molekulargenetikCatalogue = molekulargenetikCatalogue;
this.therapieplanCatalogue = therapieplanCatalogue;
this.rebiopsieCatalogue = rebiopsieCatalogue;
this.reevaluationCatalogue = reevaluationCatalogue;
this.einzelempfehlungCatalogue = einzelempfehlungCatalogue;
this.propertyCatalogue = propertyCatalogue;
}
/**
* Loads and maps a specimen using the database id
* The result does not include a diagnosis reference!
*
* @param id The database id of the procedure data set
* @return The loaded Patient data
*/
@Override
public TumorSpecimen getById(int id) {
var data = molekulargenetikCatalogue.getById(id);
var builder = TumorSpecimen.builder();
builder
.id(data.getString("id"))
.patient(getPatientReference(data.getString("patient_id")))
.type(getTumorSpecimenCoding(data.getString("materialfixierung")))
.collection(getCollection(data))
// TODO add diagnosis later
;
return builder.build();
}
/**
* Loads and maps specimens by using the referencing KPA database id
*
* @param kpaId The database id of the referencing KPA procedure data set
* @param diagnoseReferenz The reference object to the diagnosis
* @return The loaded Patient data
*/
public List<TumorSpecimen> getAllByKpaId(int kpaId, Reference diagnoseReferenz) {
var therapieplanIds = therapieplanCatalogue.getByKpaId(kpaId);
var osMolGen = therapieplanIds.stream()
.map(einzelempfehlungCatalogue::getAllByParentId)
.flatMap(einzelempfehlungen ->
einzelempfehlungen
.stream()
.map(einzelempfehlung -> einzelempfehlung.getInteger("ref_molekulargenetik"))
)
.collect(Collectors.toSet());
// Addition: Rebiopsie
osMolGen.addAll(
therapieplanIds.stream()
.map(rebiopsieCatalogue::getAllByParentId)
.flatMap(einzelempfehlungen ->
einzelempfehlungen
.stream()
.map(einzelempfehlung -> einzelempfehlung.getInteger("ref_molekulargenetik"))
)
.collect(Collectors.toSet())
);
// Addition: Reevaluation
osMolGen.addAll(
therapieplanIds.stream()
.map(reevaluationCatalogue::getAllByParentId)
.flatMap(einzelempfehlungen ->
einzelempfehlungen
.stream()
.map(einzelempfehlung -> einzelempfehlung.getInteger("ref_molekulargenetik"))
)
.collect(Collectors.toSet())
);
return osMolGen.stream()
.map(this::getById)
.peek(it -> it.setDiagnosis(diagnoseReferenz))
.collect(Collectors.toList());
}
// TODO: Kein genaues Mapping mit Formular OS.Molekulargenetik möglich - best effort
private TumorSpecimenCoding getTumorSpecimenCoding(String value) {
if (value == null) {
return null;
}
var resultBuilder = TumorSpecimenCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/type");
switch (value) {
case "2":
resultBuilder
.code(TumorSpecimenCodingCode.CRYO_FROZEN)
.display("Cryo-frozen");
break;
case "3":
resultBuilder
.code(TumorSpecimenCodingCode.FFPE)
.display("FFPE");
break;
default:
resultBuilder
.code(TumorSpecimenCodingCode.UNKNOWN)
.display("Unbekannt");
break;
}
return resultBuilder.build();
}
private Collection getCollection(ResultSet data) {
if (data == null || data.getString("entnahmemethode") == null || data.getString("probenmaterial") == null) {
return null;
}
var methodBuilder = TumorSpecimenCollectionMethodCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/method");
switch (data.getString("entnahmemethode")) {
case "B":
methodBuilder
.code(TumorSpecimenCollectionMethodCodingCode.BIOPSY)
.display("Biopsie");
break;
case "R":
methodBuilder
.code(TumorSpecimenCollectionMethodCodingCode.RESECTION)
.display("Resektat");
break;
case "LB":
methodBuilder
.code(TumorSpecimenCollectionMethodCodingCode.LIQUID_BIOPSY)
.display("Liquid Biopsy");
break;
case "Z":
methodBuilder
.code(TumorSpecimenCollectionMethodCodingCode.CYTOLOGY)
.display("Zytologie");
break;
case "U":
default:
methodBuilder
.code(TumorSpecimenCollectionMethodCodingCode.UNKNOWN)
.display("Unbekannt");
break;
}
// TODO: Kein genaues Mapping mit Formular OS.Molekulargenetik möglich - best effort
var localizationBuilder = TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization");
switch (data.getString("probenmaterial")) {
case "T":
localizationBuilder
.code(TumorSpecimenCollectionLocalizationCodingCode.PRIMARY_TUMOR)
.display("Primärtumor");
break;
case "LK":
case "M":
case "ITM":
case "SM":
localizationBuilder
.code(TumorSpecimenCollectionLocalizationCodingCode.METASTASIS)
.display("Metastase");
break;
default:
localizationBuilder
.code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN)
.display("Unbekannt");
break;
}
return Collection.builder()
.method(methodBuilder.build())
.localization(localizationBuilder.build())
.build();
}
}

View File

@ -1,6 +1,7 @@
package dev.pcvolkmer.onco.datamapper.mapper;
import dev.pcvolkmer.mv64e.mtb.Mtb;
import dev.pcvolkmer.mv64e.mtb.Reference;
import dev.pcvolkmer.onco.datamapper.PropertyCatalogue;
import dev.pcvolkmer.onco.datamapper.datacatalogues.*;
import dev.pcvolkmer.onco.datamapper.exceptions.DataAccessException;
@ -80,15 +81,26 @@ public class MtbDataMapper implements DataMapper<Mtb> {
catalogueFactory.catalogue(EcogCatalogue.class)
);
var einzelempfehlungCatalogue = catalogueFactory.catalogue(EinzelempfehlungCatalogue.class);
var therapieplanCatalogue = catalogueFactory.catalogue(TherapieplanCatalogue.class);
var therapieplanDataMapper = new TherapieplanDataMapper(
therapieplanCatalogue,
catalogueFactory.catalogue(EinzelempfehlungCatalogue.class),
einzelempfehlungCatalogue,
propertyCatalogue
);
var verwandteDataMapper = new KpaVerwandteDataMapper(catalogueFactory.catalogue(VerwandteCatalogue.class));
var molekulargenetikCatalogue = catalogueFactory.catalogue(MolekulargenetikCatalogue.class);
var molekulargenetikToSpecimenDataMapper = new MolekulargenetikToSpecimenDataMapper(
molekulargenetikCatalogue,
therapieplanCatalogue,
catalogueFactory.catalogue(RebiopsieCatalogue.class),
catalogueFactory.catalogue(ReevaluationCatalogue.class),
einzelempfehlungCatalogue,
propertyCatalogue
);
var resultBuilder = Mtb.builder();
try {
@ -96,11 +108,13 @@ public class MtbDataMapper implements DataMapper<Mtb> {
var patient = patientDataMapper.getById(Integer.parseInt(kpaPatient.getId()));
kpaPatient.setAddress(patient.getAddress());
var diagnosis = diagnosisDataMapper.getById(kpaId);
resultBuilder
.patient(kpaPatient)
.episodesOfCare(List.of(mtbEpisodeDataMapper.getById(kpaId)))
// DNPM Klinik/Anamnese
.diagnoses(List.of(diagnosisDataMapper.getById(kpaId)))
.diagnoses(List.of(diagnosis))
.guidelineProcedures(prozedurMapper.getByParentId(kpaId))
.guidelineTherapies(therapielinieMapper.getByParentId(kpaId))
.performanceStatus(ecogMapper.getByParentId(kpaId))
@ -112,6 +126,13 @@ public class MtbDataMapper implements DataMapper<Mtb> {
.map(therapieplanDataMapper::getById)
.collect(Collectors.toList())
)
// Tumorproben
.specimens(
molekulargenetikToSpecimenDataMapper.getAllByKpaId(
kpaId,
Reference.builder().id(diagnosis.getId()).type("MTBDiagnosis").build()
)
)
;
} catch (DataAccessException e) {
logger.error("Error while getting Mtb.", e);

View File

@ -0,0 +1,62 @@
package dev.pcvolkmer.onco.datamapper.datacatalogues;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class MolekulargenetikCatalogueTest {
JdbcTemplate jdbcTemplate;
MolekulargenetikCatalogue catalogue;
@BeforeEach
void setUp(@Mock JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.catalogue = MolekulargenetikCatalogue.create(jdbcTemplate);
}
@Test
void shouldUseCorrectQuery(@Mock Map<String, Object> resultSet) {
doAnswer(invocationOnMock -> List.of(resultSet))
.when(jdbcTemplate)
.queryForList(anyString(), anyInt());
this.catalogue.getById(1);
var captor = ArgumentCaptor.forClass(String.class);
verify(this.jdbcTemplate).queryForList(captor.capture(), anyInt());
assertThat(captor.getValue())
.isEqualTo("SELECT * FROM dk_molekulargenetik JOIN prozedur ON (prozedur.id = dk_molekulargenetik.id) WHERE geloescht = 0 AND prozedur.id = ?");
}
@Test
void shouldUseCorrectSubformQuery(@Mock Map<String, Object> resultSet) {
doAnswer(invocationOnMock -> List.of(resultSet))
.when(jdbcTemplate)
.queryForList(anyString(), anyInt());
this.catalogue.getAllByParentId(1);
var captor = ArgumentCaptor.forClass(String.class);
verify(this.jdbcTemplate).queryForList(captor.capture(), anyInt());
assertThat(captor.getValue())
.isEqualTo("SELECT * FROM dk_molekulargenetik JOIN prozedur ON (prozedur.id = dk_molekulargenetik.id) WHERE geloescht = 0 AND hauptprozedur_id = ?");
}
}

View File

@ -0,0 +1,62 @@
package dev.pcvolkmer.onco.datamapper.datacatalogues;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class RebiopsieCatalogueTest {
JdbcTemplate jdbcTemplate;
RebiopsieCatalogue catalogue;
@BeforeEach
void setUp(@Mock JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.catalogue = RebiopsieCatalogue.create(jdbcTemplate);
}
@Test
void shouldUseCorrectQuery(@Mock Map<String, Object> resultSet) {
doAnswer(invocationOnMock -> List.of(resultSet))
.when(jdbcTemplate)
.queryForList(anyString(), anyInt());
this.catalogue.getById(1);
var captor = ArgumentCaptor.forClass(String.class);
verify(this.jdbcTemplate).queryForList(captor.capture(), anyInt());
assertThat(captor.getValue())
.isEqualTo("SELECT * FROM dk_dnpm_uf_rebiopsie JOIN prozedur ON (prozedur.id = dk_dnpm_uf_rebiopsie.id) WHERE geloescht = 0 AND prozedur.id = ?");
}
@Test
void shouldUseCorrectSubformQuery(@Mock Map<String, Object> resultSet) {
doAnswer(invocationOnMock -> List.of(resultSet))
.when(jdbcTemplate)
.queryForList(anyString(), anyInt());
this.catalogue.getAllByParentId(1);
var captor = ArgumentCaptor.forClass(String.class);
verify(this.jdbcTemplate).queryForList(captor.capture(), anyInt());
assertThat(captor.getValue())
.isEqualTo("SELECT * FROM dk_dnpm_uf_rebiopsie JOIN prozedur ON (prozedur.id = dk_dnpm_uf_rebiopsie.id) WHERE geloescht = 0 AND hauptprozedur_id = ?");
}
}

View File

@ -0,0 +1,62 @@
package dev.pcvolkmer.onco.datamapper.datacatalogues;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class ReevaluationCatalogueTest {
JdbcTemplate jdbcTemplate;
ReevaluationCatalogue catalogue;
@BeforeEach
void setUp(@Mock JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.catalogue = ReevaluationCatalogue.create(jdbcTemplate);
}
@Test
void shouldUseCorrectQuery(@Mock Map<String, Object> resultSet) {
doAnswer(invocationOnMock -> List.of(resultSet))
.when(jdbcTemplate)
.queryForList(anyString(), anyInt());
this.catalogue.getById(1);
var captor = ArgumentCaptor.forClass(String.class);
verify(this.jdbcTemplate).queryForList(captor.capture(), anyInt());
assertThat(captor.getValue())
.isEqualTo("SELECT * FROM dk_dnpm_uf_reevaluation JOIN prozedur ON (prozedur.id = dk_dnpm_uf_reevaluation.id) WHERE geloescht = 0 AND prozedur.id = ?");
}
@Test
void shouldUseCorrectSubformQuery(@Mock Map<String, Object> resultSet) {
doAnswer(invocationOnMock -> List.of(resultSet))
.when(jdbcTemplate)
.queryForList(anyString(), anyInt());
this.catalogue.getAllByParentId(1);
var captor = ArgumentCaptor.forClass(String.class);
verify(this.jdbcTemplate).queryForList(captor.capture(), anyInt());
assertThat(captor.getValue())
.isEqualTo("SELECT * FROM dk_dnpm_uf_reevaluation JOIN prozedur ON (prozedur.id = dk_dnpm_uf_reevaluation.id) WHERE geloescht = 0 AND hauptprozedur_id = ?");
}
}

View File

@ -0,0 +1,435 @@
package dev.pcvolkmer.onco.datamapper.mapper;
import dev.pcvolkmer.mv64e.mtb.*;
import dev.pcvolkmer.onco.datamapper.PropertyCatalogue;
import dev.pcvolkmer.onco.datamapper.ResultSet;
import dev.pcvolkmer.onco.datamapper.datacatalogues.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class MolekulargenetikToSpecimenDataMapperTest {
MolekulargenetikCatalogue molekulargenetikCatalogue;
TherapieplanCatalogue therapieplanCatalogue;
RebiopsieCatalogue rebiopsieCatalogue;
ReevaluationCatalogue reevaluationCatalogue;
EinzelempfehlungCatalogue einzelempfehlungCatalogue;
PropertyCatalogue propertyCatalogue;
MolekulargenetikToSpecimenDataMapper mapper;
@BeforeEach
void setUp(
@Mock MolekulargenetikCatalogue molekulargenetikCatalogue,
@Mock TherapieplanCatalogue therapieplanCatalogue,
@Mock RebiopsieCatalogue rebiopsieCatalogue,
@Mock ReevaluationCatalogue reevaluationCatalogue,
@Mock EinzelempfehlungCatalogue einzelempfehlungCatalogue,
@Mock PropertyCatalogue propertyCatalogue
) {
this.molekulargenetikCatalogue = molekulargenetikCatalogue;
this.therapieplanCatalogue = therapieplanCatalogue;
this.rebiopsieCatalogue = rebiopsieCatalogue;
this.reevaluationCatalogue = reevaluationCatalogue;
this.einzelempfehlungCatalogue = einzelempfehlungCatalogue;
this.propertyCatalogue = propertyCatalogue;
this.mapper = new MolekulargenetikToSpecimenDataMapper(
molekulargenetikCatalogue,
therapieplanCatalogue,
rebiopsieCatalogue,
reevaluationCatalogue,
einzelempfehlungCatalogue,
propertyCatalogue
);
}
@Test
void shouldFetchAllRelatedSpecimens() {
// Mock Einzelempfehlungen ID
when(therapieplanCatalogue.getByKpaId(anyInt()))
.thenReturn(List.of(1, 2));
// Mock Rebiopsien - two referencing the same OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return List.of(ResultSet.from(Map.of("id", id, "ref_molekulargenetik", 40)));
}).when(rebiopsieCatalogue).getAllByParentId(anyInt());
// Mock Reevaluationen - two referencing the same OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return List.of(ResultSet.from(Map.of("id", id, "ref_molekulargenetik", 41)));
}).when(reevaluationCatalogue).getAllByParentId(anyInt());
// Mock Einzelempfehlungen - two referencing the same OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return List.of(ResultSet.from(Map.of("id", id, "ref_molekulargenetik", 42)));
}).when(einzelempfehlungCatalogue).getAllByParentId(anyInt());
// Mock OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return ResultSet.from(
Map.of(
"id", id,
"patient_id", 4711,
"entnahmemethode", "B",
"probenmaterial", "T"
)
);
}).when(molekulargenetikCatalogue).getById(anyInt());
var actual = this.mapper.getAllByKpaId(1, Reference.builder().build());
assertThat(actual).hasSize(3);
assertThat(actual.get(0).getId())
.isEqualTo("40");
assertThat(actual.get(1).getId())
.isEqualTo("41");
assertThat(actual.get(2).getId())
.isEqualTo("42");
assertThat(actual.get(0).getPatient())
.isEqualTo(Reference.builder().id("4711").type("Patient").build());
}
@Test
void shouldNotFetchRelatedSpecimensTwice() {
// Mock Einzelempfehlungen ID
when(therapieplanCatalogue.getByKpaId(anyInt()))
.thenReturn(List.of(1, 2));
// Mock Rebiopsien - two referencing the same OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return List.of(ResultSet.from(Map.of("id", id, "ref_molekulargenetik", 40)));
}).when(rebiopsieCatalogue).getAllByParentId(anyInt());
// Mock Reevaluationen - two referencing the same OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return List.of(ResultSet.from(Map.of("id", id, "ref_molekulargenetik", 40)));
}).when(reevaluationCatalogue).getAllByParentId(anyInt());
// Mock Einzelempfehlungen - two referencing the same OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return List.of(ResultSet.from(Map.of("id", id, "ref_molekulargenetik", 42)));
}).when(einzelempfehlungCatalogue).getAllByParentId(anyInt());
// Mock OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return ResultSet.from(
Map.of(
"id", id,
"patient_id", 4711,
"entnahmemethode", "B",
"probenmaterial", "T"
)
);
}).when(molekulargenetikCatalogue).getById(anyInt());
var actual = this.mapper.getAllByKpaId(1, Reference.builder().build());
assertThat(actual).hasSize(2);
assertThat(actual.get(0).getId())
.isEqualTo("40");
assertThat(actual.get(1).getId())
.isEqualTo("42");
}
@ParameterizedTest
@MethodSource("specimenTypeTestData")
void shouldReturnExpectedSpecimenType(String value, TumorSpecimenCoding coding) {
// Mock Einzelempfehlungen ID
when(therapieplanCatalogue.getByKpaId(anyInt()))
.thenReturn(List.of(1, 2));
// Mock Einzelempfehlungen - two referencing the same OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return List.of(ResultSet.from(Map.of("id", id, "ref_molekulargenetik", 42)));
}).when(einzelempfehlungCatalogue).getAllByParentId(anyInt());
// Mock OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return ResultSet.from(
Map.of(
"id", id,
"patient_id", 4711,
"materialfixierung", value,
"entnahmemethode", "B",
"probenmaterial", "T"
)
);
}).when(molekulargenetikCatalogue).getById(anyInt());
var actual = this.mapper.getAllByKpaId(1, Reference.builder().build());
assertThat(actual).hasSize(1);
assertThat(actual.get(0).getType()).isEqualTo(coding);
}
// Returns all available Onkostar values and - best effort - expected mapping
// See property catalogue OS.Material and https://ibmi-ut.atlassian.net/wiki/spaces/DAM/pages/698777783/ line 80
static Stream<Arguments> specimenTypeTestData() {
return Stream.of(
Arguments.of(
"0",
TumorSpecimenCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/type").code(TumorSpecimenCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"1",
TumorSpecimenCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/type").code(TumorSpecimenCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"2",
TumorSpecimenCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/type").code(TumorSpecimenCodingCode.CRYO_FROZEN).display("Cryo-frozen")
.build()
),
Arguments.of(
"3",
TumorSpecimenCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/type").code(TumorSpecimenCodingCode.FFPE).display("FFPE")
.build()
),
Arguments.of(
"4",
TumorSpecimenCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/type").code(TumorSpecimenCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"9",
TumorSpecimenCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/type").code(TumorSpecimenCodingCode.UNKNOWN).display("Unbekannt")
.build()
)
);
}
@ParameterizedTest
@MethodSource("specimenMethodTestData")
void shouldReturnExpectedSpecimenMethod(String value, TumorSpecimenCollectionMethodCoding coding) {
// Mock Einzelempfehlungen ID
when(therapieplanCatalogue.getByKpaId(anyInt()))
.thenReturn(List.of(1, 2));
// Mock Einzelempfehlungen - two referencing the same OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return List.of(ResultSet.from(Map.of("id", id, "ref_molekulargenetik", 42)));
}).when(einzelempfehlungCatalogue).getAllByParentId(anyInt());
// Mock OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return ResultSet.from(
Map.of(
"id", id,
"patient_id", 4711,
"entnahmemethode", value,
"probenmaterial", "T"
)
);
}).when(molekulargenetikCatalogue).getById(anyInt());
var actual = this.mapper.getAllByKpaId(1, Reference.builder().build());
assertThat(actual).hasSize(1);
assertThat(actual.get(0).getCollection().getMethod()).isEqualTo(coding);
}
// Returns all available Onkostar values and - best effort - expected mapping
// See property catalogue OS.MolDiagEntnahmemethode and https://ibmi-ut.atlassian.net/wiki/spaces/DAM/pages/698777783/ line 84
static Stream<Arguments> specimenMethodTestData() {
return Stream.of(
Arguments.of(
"B",
TumorSpecimenCollectionMethodCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/method").code(TumorSpecimenCollectionMethodCodingCode.BIOPSY).display("Biopsie")
.build()
),
Arguments.of(
"R",
TumorSpecimenCollectionMethodCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/method").code(TumorSpecimenCollectionMethodCodingCode.RESECTION).display("Resektat")
.build()
),
Arguments.of(
"LB",
TumorSpecimenCollectionMethodCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/method").code(TumorSpecimenCollectionMethodCodingCode.LIQUID_BIOPSY).display("Liquid Biopsy")
.build()
),
Arguments.of(
"Z",
TumorSpecimenCollectionMethodCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/method").code(TumorSpecimenCollectionMethodCodingCode.CYTOLOGY).display("Zytologie")
.build()
),
Arguments.of(
"U",
TumorSpecimenCollectionMethodCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/method").code(TumorSpecimenCollectionMethodCodingCode.UNKNOWN).display("Unbekannt")
.build()
)
);
}
@ParameterizedTest
@MethodSource("specimenLocalizationTestData")
void shouldReturnExpectedSpecimenLocalization(String value, TumorSpecimenCollectionLocalizationCoding coding) {
// Mock Einzelempfehlungen ID
when(therapieplanCatalogue.getByKpaId(anyInt()))
.thenReturn(List.of(1, 2));
// Mock Einzelempfehlungen - two referencing the same OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return List.of(ResultSet.from(Map.of("id", id, "ref_molekulargenetik", 42)));
}).when(einzelempfehlungCatalogue).getAllByParentId(anyInt());
// Mock OS.Molekulargenetik
doAnswer(invocationOnMock -> {
var id = invocationOnMock.getArgument(0, Integer.class);
return ResultSet.from(
Map.of(
"id", id,
"patient_id", 4711,
"entnahmemethode", "B",
"probenmaterial", value
)
);
}).when(molekulargenetikCatalogue).getById(anyInt());
var actual = this.mapper.getAllByKpaId(1, Reference.builder().build());
assertThat(actual).hasSize(1);
assertThat(actual.get(0).getCollection().getLocalization()).isEqualTo(coding);
}
// Returns all available Onkostar values and - best effort - expected mapping
// See property catalogue OS.Probenmaterial and https://ibmi-ut.atlassian.net/wiki/spaces/DAM/pages/698777783/ line 82
static Stream<Arguments> specimenLocalizationTestData() {
return Stream.of(
Arguments.of(
"T",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.PRIMARY_TUMOR).display("Primärtumor")
.build()
),
Arguments.of(
"R",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"LK",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.METASTASIS).display("Metastase")
.build()
),
Arguments.of(
"M",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.METASTASIS).display("Metastase")
.build()
),
Arguments.of(
"ITM",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.METASTASIS).display("Metastase")
.build()
),
Arguments.of(
"SM",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.METASTASIS).display("Metastase")
.build()
),
Arguments.of(
"KM",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"NG",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"AS",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"PLERG",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"B",
TumorSpecimenCollectionLocalizationCoding.builder().
system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"L",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"U",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN).display("Unbekannt")
.build()
),
Arguments.of(
"S",
TumorSpecimenCollectionLocalizationCoding.builder()
.system("dnpm-dip/mtb/tumor-specimen/collection/localization").code(TumorSpecimenCollectionLocalizationCodingCode.UNKNOWN).display("Unbekannt")
.build()
)
);
}
}