From a24855ec7a4f6cfaf4b10bf6a6592c3a0564770b Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer Date: Sun, 22 Jun 2025 16:26:23 +0200 Subject: [PATCH] feat: add initial Therapieplan support --- .../datacatalogues/DataCatalogueFactory.java | 2 + .../datacatalogues/TherapieplanCatalogue.java | 51 +++++++++++++++ .../onco/datamapper/mapper/MtbDataMapper.java | 12 ++++ .../mapper/TherapieplanDataMapper.java | 47 ++++++++++++++ .../TherapieplanCatalogueTest.java | 62 +++++++++++++++++++ .../mapper/TherapieplanDataMapperTest.java | 62 +++++++++++++++++++ 6 files changed, 236 insertions(+) create mode 100644 src/main/java/dev/pcvolkmer/onco/datamapper/datacatalogues/TherapieplanCatalogue.java create mode 100644 src/main/java/dev/pcvolkmer/onco/datamapper/mapper/TherapieplanDataMapper.java create mode 100644 src/test/java/dev/pcvolkmer/onco/datamapper/datacatalogues/TherapieplanCatalogueTest.java create mode 100644 src/test/java/dev/pcvolkmer/onco/datamapper/mapper/TherapieplanDataMapperTest.java diff --git a/src/main/java/dev/pcvolkmer/onco/datamapper/datacatalogues/DataCatalogueFactory.java b/src/main/java/dev/pcvolkmer/onco/datamapper/datacatalogues/DataCatalogueFactory.java index 0762dd2..d51d4e4 100644 --- a/src/main/java/dev/pcvolkmer/onco/datamapper/datacatalogues/DataCatalogueFactory.java +++ b/src/main/java/dev/pcvolkmer/onco/datamapper/datacatalogues/DataCatalogueFactory.java @@ -67,6 +67,8 @@ public class DataCatalogueFactory { return VerwandteCatalogue.create(jdbcTemplate); } else if (c == VorbefundeCatalogue.class) { return VorbefundeCatalogue.create(jdbcTemplate); + } else if (c == TherapieplanCatalogue.class) { + return TherapieplanCatalogue.create(jdbcTemplate); } throw new DataCatalogueCreationException(clazz); }); diff --git a/src/main/java/dev/pcvolkmer/onco/datamapper/datacatalogues/TherapieplanCatalogue.java b/src/main/java/dev/pcvolkmer/onco/datamapper/datacatalogues/TherapieplanCatalogue.java new file mode 100644 index 0000000..9e0bd56 --- /dev/null +++ b/src/main/java/dev/pcvolkmer/onco/datamapper/datacatalogues/TherapieplanCatalogue.java @@ -0,0 +1,51 @@ +package dev.pcvolkmer.onco.datamapper.datacatalogues; + +import dev.pcvolkmer.onco.datamapper.ResultSet; +import dev.pcvolkmer.onco.datamapper.exceptions.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Load raw result sets from database table 'dk_dnpm_therapieplan' + * + * @author Paul-Christian Volkmer + * @since 0.1 + */ +public class TherapieplanCatalogue extends AbstractDataCatalogue { + + private TherapieplanCatalogue(JdbcTemplate jdbcTemplate) { + super(jdbcTemplate); + } + + @Override + protected String getTableName() { + return "dk_dnpm_therapieplan"; + } + + public static TherapieplanCatalogue create(JdbcTemplate jdbcTemplate) { + return new TherapieplanCatalogue(jdbcTemplate); + } + + /** + * Get procedure IDs by related Klinik/Anamnese procedure id + * + * @param kpaId The procedure id + * @return The procedure ids + */ + public List getByKpaId(int kpaId) { + return this.jdbcTemplate.queryForList( + String.format( + "SELECT prozedur.id AS procedure_id FROM %s JOIN prozedur ON (prozedur.id = %s.id) WHERE geloescht = 0 AND ref_dnpm_klinikanamnese = ?", + getTableName(), + getTableName() + ), + kpaId) + .stream() + .map(ResultSet::from) + .map(rs -> rs.getInteger("procedure_id")) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/dev/pcvolkmer/onco/datamapper/mapper/MtbDataMapper.java b/src/main/java/dev/pcvolkmer/onco/datamapper/mapper/MtbDataMapper.java index 4e7e64d..3233453 100644 --- a/src/main/java/dev/pcvolkmer/onco/datamapper/mapper/MtbDataMapper.java +++ b/src/main/java/dev/pcvolkmer/onco/datamapper/mapper/MtbDataMapper.java @@ -10,6 +10,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; import java.util.List; +import java.util.stream.Collectors; /** * Mapper class to load and map Mtb files from database @@ -78,6 +79,9 @@ public class MtbDataMapper implements DataMapper { catalogueFactory.catalogue(EcogCatalogue.class) ); + var therapieplanCatalogue = catalogueFactory.catalogue(TherapieplanCatalogue.class); + var therapieplanDataMapper = new TherapieplanDataMapper(therapieplanCatalogue, propertyCatalogue); + var resultBuilder = Mtb.builder(); try { @@ -87,10 +91,18 @@ public class MtbDataMapper implements DataMapper { resultBuilder .patient(kpaPatient) + // DNPM Klinik/Anamnese .diagnoses(List.of(diagnosisDataMapper.getById(kpaId))) .guidelineProcedures(prozedurMapper.getByParentId(kpaId)) .guidelineTherapies(therapielinieMapper.getByParentId(kpaId)) .performanceStatus(ecogMapper.getByParentId(kpaId)) + // DNPM Therapieplan + .carePlans( + therapieplanCatalogue + .getByKpaId(kpaId).stream() + .map(therapieplanDataMapper::getById) + .collect(Collectors.toList()) + ) ; } catch (DataAccessException e) { logger.error("Error while getting Mtb.", e); diff --git a/src/main/java/dev/pcvolkmer/onco/datamapper/mapper/TherapieplanDataMapper.java b/src/main/java/dev/pcvolkmer/onco/datamapper/mapper/TherapieplanDataMapper.java new file mode 100644 index 0000000..9c35df6 --- /dev/null +++ b/src/main/java/dev/pcvolkmer/onco/datamapper/mapper/TherapieplanDataMapper.java @@ -0,0 +1,47 @@ +package dev.pcvolkmer.onco.datamapper.mapper; + +import dev.pcvolkmer.mv64e.mtb.MtbCarePlan; +import dev.pcvolkmer.onco.datamapper.PropertyCatalogue; +import dev.pcvolkmer.onco.datamapper.datacatalogues.TherapieplanCatalogue; + +import static dev.pcvolkmer.onco.datamapper.mapper.MapperUtils.getPatientReference; + +/** + * Mapper class to load and map patient data from database table 'dk_dnpm_therapieplan' + * + * @author Paul-Christian Volkmer + * @since 0.1 + */ +public class TherapieplanDataMapper implements DataMapper { + + private final TherapieplanCatalogue therapieplanCatalogue; + private final PropertyCatalogue propertyCatalogue; + + public TherapieplanDataMapper( + final TherapieplanCatalogue therapieplanCatalogue, + final PropertyCatalogue propertyCatalogue + ) { + this.therapieplanCatalogue = therapieplanCatalogue; + this.propertyCatalogue = propertyCatalogue; + } + + /** + * Loads and maps a ca plan using the database id + * + * @param id The database id of the procedure data set + * @return The loaded Patient data + */ + @Override + public MtbCarePlan getById(int id) { + var therapieplanData = therapieplanCatalogue.getById(id); + + var builder = MtbCarePlan.builder(); + builder + .id(therapieplanData.getString("id")) + .patient(getPatientReference(therapieplanData.getString("patient_id"))) + .issuedOn(therapieplanData.getDate("datum")) + ; + return builder.build(); + } + +} diff --git a/src/test/java/dev/pcvolkmer/onco/datamapper/datacatalogues/TherapieplanCatalogueTest.java b/src/test/java/dev/pcvolkmer/onco/datamapper/datacatalogues/TherapieplanCatalogueTest.java new file mode 100644 index 0000000..59739d6 --- /dev/null +++ b/src/test/java/dev/pcvolkmer/onco/datamapper/datacatalogues/TherapieplanCatalogueTest.java @@ -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 TherapieplanCatalogueTest { + + JdbcTemplate jdbcTemplate; + TherapieplanCatalogue catalogue; + + @BeforeEach + void setUp(@Mock JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + this.catalogue = TherapieplanCatalogue.create(jdbcTemplate); + } + + @Test + void shouldUseCorrectQuery(@Mock Map 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_therapieplan JOIN prozedur ON (prozedur.id = dk_dnpm_therapieplan.id) WHERE geloescht = 0 AND prozedur.id = ?"); + } + + @Test + void shouldUseCorrectQueryForKpaRelatedProcedures(@Mock Map resultSet) { + doAnswer(invocationOnMock -> List.of(resultSet)) + .when(jdbcTemplate) + .queryForList(anyString(), anyInt()); + + this.catalogue.getByKpaId(1); + + var captor = ArgumentCaptor.forClass(String.class); + verify(this.jdbcTemplate).queryForList(captor.capture(), anyInt()); + + assertThat(captor.getValue()) + .isEqualTo("SELECT prozedur.id AS procedure_id FROM dk_dnpm_therapieplan JOIN prozedur ON (prozedur.id = dk_dnpm_therapieplan.id) WHERE geloescht = 0 AND ref_dnpm_klinikanamnese = ?"); + } + +} diff --git a/src/test/java/dev/pcvolkmer/onco/datamapper/mapper/TherapieplanDataMapperTest.java b/src/test/java/dev/pcvolkmer/onco/datamapper/mapper/TherapieplanDataMapperTest.java new file mode 100644 index 0000000..e7f1ed0 --- /dev/null +++ b/src/test/java/dev/pcvolkmer/onco/datamapper/mapper/TherapieplanDataMapperTest.java @@ -0,0 +1,62 @@ +package dev.pcvolkmer.onco.datamapper.mapper; + +import dev.pcvolkmer.mv64e.mtb.MtbCarePlan; +import dev.pcvolkmer.mv64e.mtb.Reference; +import dev.pcvolkmer.onco.datamapper.PropertyCatalogue; +import dev.pcvolkmer.onco.datamapper.ResultSet; +import dev.pcvolkmer.onco.datamapper.datacatalogues.TherapieplanCatalogue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +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; + +@ExtendWith(MockitoExtension.class) +class TherapieplanDataMapperTest { + + TherapieplanCatalogue therapieplanCatalogue; + PropertyCatalogue propertyCatalogue; + + TherapieplanDataMapper dataMapper; + + @BeforeEach + void setUp( + @Mock TherapieplanCatalogue therapieplanCatalogue, + @Mock PropertyCatalogue propertyCatalogue + ) { + this.therapieplanCatalogue = therapieplanCatalogue; + this.propertyCatalogue = propertyCatalogue; + this.dataMapper = new TherapieplanDataMapper(therapieplanCatalogue, propertyCatalogue); + } + + @Test + void shouldCreateCarePlan(@Mock ResultSet resultSet) { + final var testData = Map.of( + "id", "1", + "patient_id", "42" + ); + + doAnswer(invocationOnMock -> { + var columnName = invocationOnMock.getArgument(0, String.class); + return testData.get(columnName); + }).when(resultSet).getString(anyString()); + + doAnswer(invocationOnMock -> resultSet) + .when(therapieplanCatalogue) + .getById(anyInt()); + + var actual = this.dataMapper.getById(1); + assertThat(actual).isInstanceOf(MtbCarePlan.class); + assertThat(actual.getId()).isEqualTo("1"); + assertThat(actual.getPatient()) + .isEqualTo(Reference.builder().id("42").type("Patient").build()); + } + +}