#27: WIP
All checks were successful
Quality Check / Linting Check (push) Successful in 18s
Quality Check / Linting Check (pull_request) Successful in 23s
Quality Check / Javadoc Check (push) Successful in 41s
Quality Check / Javadoc Check (pull_request) Successful in 38s

Signed-off-by: Dominik Säume <Dominik.Saeume@hmmh.de>
This commit is contained in:
Dominik Säume 2024-05-22 11:56:53 +02:00 committed by Dominik Säume
parent 275aa3252a
commit e184950622
Signed by: SZUT-Dominik
GPG key ID: 67D15BB250B41E7C
9 changed files with 384 additions and 181 deletions

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true"> <component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="nursingHome.db" uuid="5a5b8be1-080b-4129-b89d-42f1ea832b90"> <data-source source="LOCAL" name="Database" uuid="5a5b8be1-080b-4129-b89d-42f1ea832b90">
<driver-ref>sqlite.xerial</driver-ref> <driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize> <synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver> <jdbc-driver>org.sqlite.JDBC</jdbc-driver>

Binary file not shown.

View file

@ -1,17 +1,17 @@
package de.hitec.nhplus.fixtures; package de.hitec.nhplus.fixtures;
import de.hitec.nhplus.Main;
import de.hitec.nhplus.datastorage.DaoFactory;
import de.hitec.nhplus.medication.Ingredient;
import de.hitec.nhplus.medication.Medication;
import de.hitec.nhplus.medication.database.MedicationDao;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import de.hitec.nhplus.Main;
import de.hitec.nhplus.datastorage.DaoFactory;
import de.hitec.nhplus.medication.Ingredient;
import de.hitec.nhplus.medication.Medication;
import de.hitec.nhplus.medication.database.MedicationDao;
/** /**
* {@link Fixture} for {@link Medication}. * {@link Fixture} for {@link Medication}.
* *
@ -20,11 +20,13 @@ import java.util.*;
public class MedicationFixture implements Fixture<Medication> { public class MedicationFixture implements Fixture<Medication> {
private static final String SCHEMA = "/de/hitec/nhplus/medication/database/Medication.sql"; private static final String SCHEMA = "/de/hitec/nhplus/medication/database/Medication.sql";
private static final String INGREDIENT_SCHEMA = "/de/hitec/nhplus/medication/database/Medication_Ingredient.sql"; private static final String INGREDIENT_SCHEMA = "/de/hitec/nhplus/medication/database/Medication_Ingredient.sql";
private static final String ALTERNATIVE_SCHEMA = "/de/hitec/nhplus/medication/database/Medication_Alternative.sql";
@Override @Override
public void dropTable(Connection connection) throws SQLException { public void dropTable(Connection connection) throws SQLException {
connection.createStatement().execute("DROP TABLE IF EXISTS medication"); connection.createStatement().execute("DROP TABLE IF EXISTS medication");
connection.createStatement().execute("DROP TABLE IF EXISTS medication_ingredient"); connection.createStatement().execute("DROP TABLE IF EXISTS medication_ingredient");
connection.createStatement().execute("DROP TABLE IF EXISTS medication_alternative");
} }
@Override @Override
@ -32,16 +34,25 @@ public class MedicationFixture implements Fixture<Medication> {
final InputStream schema = Main.class.getResourceAsStream(SCHEMA); final InputStream schema = Main.class.getResourceAsStream(SCHEMA);
final InputStream ingredientSchema = Main.class.getResourceAsStream(INGREDIENT_SCHEMA); final InputStream ingredientSchema = Main.class.getResourceAsStream(INGREDIENT_SCHEMA);
final InputStream alternativeSchema = Main.class.getResourceAsStream(ALTERNATIVE_SCHEMA);
assert schema != null; assert schema != null;
assert ingredientSchema != null; assert ingredientSchema != null;
assert alternativeSchema != null;
String SQL = new Scanner(schema, StandardCharsets.UTF_8) String SQL = new Scanner(schema, StandardCharsets.UTF_8)
.useDelimiter("\\A") .useDelimiter("\\A")
.next(); .next();
String ingredientSQL = ";" + new Scanner(ingredientSchema, StandardCharsets.UTF_8) String ingredientSQL = ";" + new Scanner(ingredientSchema, StandardCharsets.UTF_8)
.useDelimiter("\\A") .useDelimiter("\\A")
.next(); .next();
String alternativeSQL = ";" + new Scanner(alternativeSchema, StandardCharsets.UTF_8)
.useDelimiter("\\A")
.next();
connection.createStatement().execute(SQL); connection.createStatement().execute(SQL);
connection.createStatement().execute(ingredientSQL); connection.createStatement().execute(ingredientSQL);
connection.createStatement().execute(alternativeSQL);
} }
@ -67,86 +78,106 @@ public class MedicationFixture implements Fixture<Medication> {
Ingredient warfarinnatrium = new Ingredient("Warfarinnatrium"); Ingredient warfarinnatrium = new Ingredient("Warfarinnatrium");
medications.add(new Medication( medications.add(new Medication(
"Metformin", "Metformin",
"AstraZeneca", "AstraZeneca",
List.of( List.of(
metforminhydrochlorid, metforminhydrochlorid,
cellulose, cellulose,
povidon, povidon,
magnesiumstearat magnesiumstearat
), ),
"Übelkeit, Durchfall, Laktatazidose (selten)", "Übelkeit, Durchfall, Laktatazidose (selten)",
"Oral", "Oral",
100 100,
new ArrayList<>()
)); ));
medications.add(new Medication( medications.add(new Medication(
"Lisinopril", "Lisinopril",
"Teva Pharmaceuticals", "Teva Pharmaceuticals",
List.of( List.of(
lisinoprilDihydrat, lisinoprilDihydrat,
mannitol, mannitol,
calciumphosphat, calciumphosphat,
magnesiumstearat magnesiumstearat
), ),
"Schwindel, trockener Husten", "Schwindel, trockener Husten",
"Oral", "Oral",
150 150,
new ArrayList<>()
)); ));
medications.add(new Medication( medications.add(new Medication(
"Simvastatin", "Simvastatin",
"Mylan", "Mylan",
List.of( List.of(
simvastatin, simvastatin,
laktose, laktose,
cellulose, cellulose,
magnesiumstearat magnesiumstearat
), ),
"Muskelschmerzen, Leberprobleme(selten)", "Muskelschmerzen, Leberprobleme(selten)",
"Oral", "Oral",
80 80,
new ArrayList<>()
)); ));
medications.add(new Medication( medications.add(new Medication(
"Enoxaparin", "Enoxaparin",
"Sanofi", "Sanofi",
List.of( List.of(
enoxaparinNatrium, enoxaparinNatrium,
benzylalkohol, benzylalkohol,
wasser wasser
), ),
"Blutungen, Reaktionen an der Injektionsstelle", "Blutungen, Reaktionen an der Injektionsstelle",
"Unterhautinjektion", "Unterhautinjektion",
120 120,
new ArrayList<>()
)); ));
medications.add(new Medication( medications.add(new Medication(
"Levothyroxin", "Levothyroxin",
"Sandoz", "Sandoz",
List.of( List.of(
levothyroxinnatrium, levothyroxinnatrium,
laktose, laktose,
staerke, staerke,
akaziengummi akaziengummi
), ),
"Herzrasen, Gewichtsverlust", "Herzrasen, Gewichtsverlust",
"Oral", "Oral",
90 90,
new ArrayList<>()
)); ));
medications.add(new Medication( medications.add(new Medication(
"Warfarin", "Warfarin",
"Apotex Inc.", "Apotex Inc.",
List.of( List.of(
warfarinnatrium, warfarinnatrium,
laktose, laktose,
staerke, staerke,
magnesiumstearat magnesiumstearat
), ),
"Blutungen, Blutergüsse", "Blutungen, Blutergüsse",
"Oral", "Oral",
110 110,
new ArrayList<>()
)); ));
MedicationDao dao = DaoFactory.getInstance().createMedicationDAO(); MedicationDao dao = DaoFactory.getInstance().createMedicationDAO();
Map<String, Medication> medicationsByName = new HashMap<>();
for (Medication medication : medications) { for (Medication medication : medications) {
dao.create(medication); dao.create(medication);
}
List<Medication> createdMedications = dao.readAll();
Map<String, Medication> medicationsByName = new HashMap<>();
for (Medication medication : createdMedications){
switch (medication.getName()){
case "Warfarin":
medication.setAlternativeMedication(List.of(
createdMedications.get(0),
createdMedications.get(3)
));
break;
default:
break;
}
dao.update(medication);
medicationsByName.put(medication.getName(), medication); medicationsByName.put(medication.getName(), medication);
} }
return medicationsByName; return medicationsByName;

View file

@ -48,6 +48,8 @@ public class AllMedicationController {
private TableColumn<Medication, String> columnAdministrationMethod; private TableColumn<Medication, String> columnAdministrationMethod;
@FXML @FXML
private TableColumn<Medication, Integer> columnCurrentStock; private TableColumn<Medication, Integer> columnCurrentStock;
@FXML
public TableColumn<Medication, String> columnAlternativeMedication;
private final ObservableList<Medication> medications = FXCollections.observableArrayList(); private final ObservableList<Medication> medications = FXCollections.observableArrayList();
private MedicationDao dao; private MedicationDao dao;
@ -77,13 +79,29 @@ public class AllMedicationController {
return new SimpleStringProperty( return new SimpleStringProperty(
ingredients ingredients
.stream() .stream()
.map(ingredient -> ingredient.getName()) .map(Ingredient::getName)
.collect(Collectors.joining("\n")) .collect(Collectors.joining("\n"))
); );
}); });
this.columnPossibleSideEffects.setCellValueFactory(new PropertyValueFactory<>("possibleSideEffects")); this.columnPossibleSideEffects.setCellValueFactory(new PropertyValueFactory<>("possibleSideEffects"));
this.columnAdministrationMethod.setCellValueFactory(new PropertyValueFactory<>("administrationMethod")); this.columnAdministrationMethod.setCellValueFactory(new PropertyValueFactory<>("administrationMethod"));
this.columnCurrentStock.setCellValueFactory(new PropertyValueFactory<>("currentStock")); this.columnCurrentStock.setCellValueFactory(new PropertyValueFactory<>("currentStock"));
this.columnAlternativeMedication.setCellValueFactory(
cellData -> {
Medication medication = cellData.getValue();
List<Medication> alternatives = medication.getAlternativeMedication();
if (alternatives.isEmpty()) {
return new SimpleStringProperty("");
}
return new SimpleStringProperty(
alternatives
.stream()
.map(med -> med.getName() + ", " + med.getManufacturer())
.collect(Collectors.joining("\n"))
);
}
);
this.tableView.setItems(this.medications); this.tableView.setItems(this.medications);
} }

View file

@ -17,12 +17,13 @@ import java.util.stream.Collectors;
*/ */
public class Medication { public class Medication {
private SimpleIntegerProperty id; private SimpleIntegerProperty id;
private final SimpleStringProperty name; private SimpleStringProperty name;
private final SimpleStringProperty manufacturer; private SimpleStringProperty manufacturer;
private final SimpleListProperty<Ingredient> ingredients; private SimpleListProperty<Ingredient> ingredients;
private final SimpleStringProperty possibleSideEffects; private SimpleStringProperty possibleSideEffects;
private final SimpleStringProperty administrationMethod; private SimpleStringProperty administrationMethod;
private final SimpleIntegerProperty currentStock; private SimpleIntegerProperty currentStock;
private SimpleListProperty<Medication> alternativeMedication;
/** /**
* This constructor allows instantiating a {@link Medication} object, * This constructor allows instantiating a {@link Medication} object,
@ -37,7 +38,8 @@ public class Medication {
List<Ingredient> ingredients, List<Ingredient> ingredients,
String possibleSideEffects, String possibleSideEffects,
String administrationMethod, String administrationMethod,
int currentStock int currentStock,
List<Medication> alternativeMedication
) { ) {
this.name = new SimpleStringProperty(name); this.name = new SimpleStringProperty(name);
this.manufacturer = new SimpleStringProperty(manufacturer); this.manufacturer = new SimpleStringProperty(manufacturer);
@ -45,6 +47,7 @@ public class Medication {
this.possibleSideEffects = new SimpleStringProperty(possibleSideEffects); this.possibleSideEffects = new SimpleStringProperty(possibleSideEffects);
this.administrationMethod = new SimpleStringProperty(administrationMethod); this.administrationMethod = new SimpleStringProperty(administrationMethod);
this.currentStock = new SimpleIntegerProperty(currentStock); this.currentStock = new SimpleIntegerProperty(currentStock);
this.alternativeMedication = new SimpleListProperty<>(FXCollections.observableArrayList(alternativeMedication));
} }
/** /**
@ -57,7 +60,8 @@ public class Medication {
List<Ingredient> ingredients, List<Ingredient> ingredients,
String possibleSideEffects, String possibleSideEffects,
String administrationMethod, String administrationMethod,
int currentStock int currentStock,
List<Medication> alternativeMedication
) { ) {
this.id = new SimpleIntegerProperty(id); this.id = new SimpleIntegerProperty(id);
this.name = new SimpleStringProperty(name); this.name = new SimpleStringProperty(name);
@ -66,6 +70,21 @@ public class Medication {
this.possibleSideEffects = new SimpleStringProperty(possibleSideEffects); this.possibleSideEffects = new SimpleStringProperty(possibleSideEffects);
this.administrationMethod = new SimpleStringProperty(administrationMethod); this.administrationMethod = new SimpleStringProperty(administrationMethod);
this.currentStock = new SimpleIntegerProperty(currentStock); this.currentStock = new SimpleIntegerProperty(currentStock);
this.alternativeMedication = new SimpleListProperty<>(FXCollections.observableArrayList(alternativeMedication));
}
public void replace(Medication medication){
if(medication == null){
return;
}
this.id = medication.idProperty();
this.name = medication.nameProperty();
this.manufacturer = medication.manufacturerProperty();
this.ingredients = medication.ingredientsProperty();
this.possibleSideEffects = medication.possibleSideEffectsProperty();
this.administrationMethod = medication.administrationMethodProperty();
this.currentStock = medication.currentStockProperty();
this.alternativeMedication = medication.alternativeMedicationProperty();
} }
public int getId() { public int getId() {
@ -124,6 +143,18 @@ public class Medication {
this.possibleSideEffects.set(possibleSideEffects); this.possibleSideEffects.set(possibleSideEffects);
} }
public ObservableList<Medication> getAlternativeMedication() {
return alternativeMedication.get();
}
public SimpleListProperty<Medication> alternativeMedicationProperty() {
return alternativeMedication;
}
public void setAlternativeMedication(List<Medication> alternativeMedication) {
this.alternativeMedication.set(FXCollections.observableArrayList(alternativeMedication));
}
public String getAdministrationMethod() { public String getAdministrationMethod() {
return administrationMethod.get(); return administrationMethod.get();
} }
@ -162,6 +193,7 @@ public class Medication {
.add("Possible Side Effects: " + this.getPossibleSideEffects()) .add("Possible Side Effects: " + this.getPossibleSideEffects())
.add("Administration Method: " + this.getAdministrationMethod()) .add("Administration Method: " + this.getAdministrationMethod())
.add("Current Stock: " + this.getCurrentStock()) .add("Current Stock: " + this.getCurrentStock())
.add("Alternative Medication" + this.getAlternativeMedication())
.toString(); .toString();
} }

View file

@ -1,10 +1,9 @@
package de.hitec.nhplus.medication; package de.hitec.nhplus.medication;
import java.util.List;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.ListCell; import javafx.scene.control.ListCell;
@ -13,6 +12,8 @@ import javafx.scene.layout.BorderPane;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import org.controlsfx.control.SearchableComboBox; import org.controlsfx.control.SearchableComboBox;
import java.util.List;
/** /**
* A custom implementation of the {@link ListCell} for {@link Ingredient}s. * A custom implementation of the {@link ListCell} for {@link Ingredient}s.
* This implementation contains an automatic resizing of the parent {@link ListView}. * This implementation contains an automatic resizing of the parent {@link ListView}.
@ -21,20 +22,19 @@ import org.controlsfx.control.SearchableComboBox;
*/ */
public class MedicationListCell extends ListCell<Medication> { public class MedicationListCell extends ListCell<Medication> {
private final Button deleteButton; private final Button deleteButton;
private SearchableComboBox<Medication> comboBox; private final SearchableComboBox<Medication> comboBox;
private static final double BUILTIN_BORDER_WIDTH = 1; private static final double BUILTIN_BORDER_WIDTH = 1;
private static final double CELL_SPACING = 4; private static final double CELL_SPACING = 4;
private static final double CELL_PADDING = 4; private static final double CELL_PADDING = 4;
private static final double BUTTON_PADDING_X = 8; private static final double BUTTON_PADDING_X = 8;
private static final double BUTTON_PADDING_Y = 4; private static final double BUTTON_PADDING_Y = 4;
private final double totalSpacing; private final double totalSpacing;
private final List<Medication> allOtherMedications; private boolean firstUpdate = true;
public MedicationListCell(List<Medication> allOtherMedications) { public MedicationListCell(List<Medication> allOtherMedications) {
this.allOtherMedications = allOtherMedications;
this.setPadding(new Insets(CELL_PADDING)); this.setPadding(new Insets(CELL_PADDING));
comboBox = new SearchableComboBox(); comboBox = new SearchableComboBox<>();
ObservableList<Medication> list = FXCollections.observableArrayList(); ObservableList<Medication> list = FXCollections.observableArrayList();
list.setAll(allOtherMedications); list.setAll(allOtherMedications);
comboBox.setItems(list); comboBox.setItems(list);
@ -45,12 +45,12 @@ public class MedicationListCell extends ListCell<Medication> {
deleteButton = new Button("-"); deleteButton = new Button("-");
deleteButton.setPadding(new Insets( deleteButton.setPadding(new Insets(
BUTTON_PADDING_Y, BUTTON_PADDING_Y,
BUTTON_PADDING_X, BUTTON_PADDING_X,
BUTTON_PADDING_Y, BUTTON_PADDING_Y,
BUTTON_PADDING_X BUTTON_PADDING_X
)); ));
deleteButton.setOnAction(event -> getListView().getItems().remove(getItem())); deleteButton.setOnAction(this::handleDeleteButton);
// Calculate Delete Button Width // Calculate Delete Button Width
Text textNode = new Text(deleteButton.getText()); Text textNode = new Text(deleteButton.getText());
@ -58,34 +58,49 @@ public class MedicationListCell extends ListCell<Medication> {
double calculatedDeleteButtonWidth = textNode.getLayoutBounds().getWidth() + BUTTON_PADDING_X * 2; double calculatedDeleteButtonWidth = textNode.getLayoutBounds().getWidth() + BUTTON_PADDING_X * 2;
totalSpacing = BUILTIN_BORDER_WIDTH * 2 // List View totalSpacing = BUILTIN_BORDER_WIDTH * 2 // List View
+ CELL_PADDING * 2 + CELL_PADDING * 2
+ CELL_SPACING + CELL_SPACING
+ calculatedDeleteButtonWidth; + calculatedDeleteButtonWidth;
} }
/**
* A Callback for use as a Listener for the {@link MedicationListCell#comboBox}.
*/
private void onComboBoxChange( private void onComboBoxChange(
ObservableValue<? extends Medication> observableValue, ObservableValue<? extends Medication> observableValue,
Medication oldValue, Medication oldValue,
Medication newValue Medication newValue
) { ) {
getItem().replace(comboBox.getValue());
ListView<Medication> listView = getListView(); ListView<Medication> listView = getListView();
double max = listView.lookupAll("*") double max = listView.lookupAll("*")
.stream() .stream()
.filter(node -> node instanceof MedicationListCell) .filter(node -> node instanceof MedicationListCell)
.mapToDouble(node -> getComboBoxWidth()) .mapToDouble(node -> comboBox.getWidth())
.max() .max()
.orElse(0); .orElse(0);
listView.setMinWidth(max + totalSpacing); listView.setMinWidth(max + totalSpacing);
} }
@Override @Override
protected void updateItem(Medication item, boolean empty) { protected void updateItem(Medication item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
if (empty || item == null) { if (empty || item == null) {
setGraphic(null); setGraphic(null);
} else { } else {
if (
firstUpdate
&& comboBox.getSelectionModel().getSelectedItem() == null
&& item.getName() != null
&& comboBox.getItems().contains(item)
) {
comboBox.getSelectionModel().select(item);
}
firstUpdate = false;
BorderPane cellPane = new BorderPane(); BorderPane cellPane = new BorderPane();
cellPane.setCenter(comboBox); cellPane.setCenter(comboBox);
cellPane.setRight(deleteButton); cellPane.setRight(deleteButton);
@ -94,10 +109,6 @@ public class MedicationListCell extends ListCell<Medication> {
} }
} }
private double getComboBoxWidth(){
return comboBox.getWidth();
}
private ListCell comboBoxFactory(Object param) { private ListCell comboBoxFactory(Object param) {
return new ListCell<Medication>() { return new ListCell<Medication>() {
@ -105,9 +116,9 @@ public class MedicationListCell extends ListCell<Medication> {
protected void updateItem(Medication med, boolean empty) { protected void updateItem(Medication med, boolean empty) {
super.updateItem(med, empty); super.updateItem(med, empty);
setText( setText(
empty || med == null empty || med == null
? null ? null
: med.getComboBoxString() : med.getComboBoxString()
); );
} }
}; };
@ -119,11 +130,17 @@ public class MedicationListCell extends ListCell<Medication> {
protected void updateItem(Medication med, boolean empty) { protected void updateItem(Medication med, boolean empty) {
super.updateItem(med, empty); super.updateItem(med, empty);
setText( setText(
empty || med == null empty || med == null
? comboBox.getPromptText() ? comboBox.getPromptText()
: med.getComboBoxString() : med.getComboBoxString()
); );
} }
}; };
} }
private void handleDeleteButton(ActionEvent event) {
if (getItem() == null) {
getListView().getItems().remove(getItem());
}
}
} }

View file

@ -1,11 +1,5 @@
package de.hitec.nhplus.medication; package de.hitec.nhplus.medication;
import static de.hitec.nhplus.utils.Validator.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@ -16,6 +10,15 @@ import javafx.scene.control.TextArea;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.stage.Stage; import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static de.hitec.nhplus.utils.Validator.*;
/** /**
* The controller for creating and editing a specific {@link Medication}. * The controller for creating and editing a specific {@link Medication}.
* *
@ -53,9 +56,9 @@ public class MedicationModalController {
*/ */
@FXML @FXML
public void initialize( public void initialize(
Stage stage, Stage stage,
AllMedicationController controller, AllMedicationController controller,
Medication medication Medication medication
) { ) {
this.stage = stage; this.stage = stage;
this.controller = controller; this.controller = controller;
@ -65,12 +68,13 @@ public class MedicationModalController {
} else { } else {
isNewMedication = true; isNewMedication = true;
this.medication = new Medication( this.medication = new Medication(
"", "",
"", "",
new ArrayList<>(), new ArrayList<>(),
"", "",
"", "",
0 0,
new ArrayList<>()
); );
this.buttonSave.setDisable(true); this.buttonSave.setDisable(true);
} }
@ -85,9 +89,9 @@ public class MedicationModalController {
ChangeListener<String> inputMedicationValidationListener = (observableValue, oldText, newText) -> { ChangeListener<String> inputMedicationValidationListener = (observableValue, oldText, newText) -> {
boolean isValid = isValidMedicationName(textFieldName.getText()) boolean isValid = isValidMedicationName(textFieldName.getText())
&& isValidMedicationManufacturer(textFieldManufacturer.getText()) && isValidMedicationManufacturer(textFieldManufacturer.getText())
&& isValidMedicationAdministrationMethod(textFieldAdministrationMethod.getText()) && isValidMedicationAdministrationMethod(textFieldAdministrationMethod.getText())
&& isValidStock(textFieldCurrentStock.getText()); && isValidStock(textFieldCurrentStock.getText());
this.buttonSave.setDisable(!isValid); this.buttonSave.setDisable(!isValid);
}; };
@ -103,13 +107,18 @@ public class MedicationModalController {
*/ */
private void showData() { private void showData() {
ingredients.setAll(medication.getIngredients()); ingredients.setAll(medication.getIngredients());
alternativeMediaction.setAll(medication.getAlternativeMedication());
Map<Integer, Medication> currentAlternatives = alternativeMediaction
.stream()
.collect(Collectors.toMap(Medication::getId, med -> med));
try { try {
allOtherMedications = controller.getDao().readAll(); allOtherMedications = controller.getDao().readAll();
if (!isNewMedication) { if (!isNewMedication) {
allOtherMedications = allOtherMedications allOtherMedications = allOtherMedications
.stream() .stream()
.filter(med -> med.getId() != medication.getId()) .filter(med -> med.getId() != medication.getId())
.toList(); .map(med -> currentAlternatives.getOrDefault(med.getId(), med))
.toList();
} }
} catch (Exception exception) { } catch (Exception exception) {
exception.printStackTrace(); exception.printStackTrace();
@ -129,12 +138,21 @@ public class MedicationModalController {
this.medication.setCurrentStock(Integer.parseInt(textFieldCurrentStock.getText())); this.medication.setCurrentStock(Integer.parseInt(textFieldCurrentStock.getText()));
this.medication.setPossibleSideEffects(textAreaPossibleSideEffects.getText()); this.medication.setPossibleSideEffects(textAreaPossibleSideEffects.getText());
this.medication.setIngredients(ingredients this.medication.setIngredients(ingredients
.stream() .stream()
.map(Ingredient::getName) .map(Ingredient::getName)
.distinct() .distinct()
.filter(Predicate.not(String::isEmpty)) .filter(Predicate.not(String::isEmpty))
.map(Ingredient::new) .map(Ingredient::new)
.toList() .toList()
);
this.medication.setAlternativeMedication(
alternativeMediaction
.stream()
.distinct()
.filter(Predicate.not(Objects::isNull))
.filter(Predicate.not(med -> med.idProperty() == null))
.toList()
); );
if (isNewMedication) { if (isNewMedication) {
@ -159,12 +177,13 @@ public class MedicationModalController {
public void handleAddAlternativeMedication() { public void handleAddAlternativeMedication() {
alternativeMediaction.add(new Medication( alternativeMediaction.add(new Medication(
null, null,
null, null,
List.of(), new ArrayList<>(),
null, null,
null, null,
-1 -1,
new ArrayList<>()
)); ));
} }
} }

View file

@ -8,10 +8,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* The {@link MedicationDao} is an implementation of the{@link de.hitec.nhplus.datastorage.Dao Dao} * The {@link MedicationDao} is an implementation of the{@link de.hitec.nhplus.datastorage.Dao Dao}
@ -63,36 +60,45 @@ public class MedicationDao implements Dao<Medication> {
ingredientStatement.setString(2, ingredient.getName()); ingredientStatement.setString(2, ingredient.getName());
ingredientStatement.execute(); ingredientStatement.execute();
} }
final String alternativeMedicationSQL = """
INSERT INTO medication_alternative
(id, alternativeId)
VALUES (?, ?);
""";
for (Medication alternative : medication.getAlternativeMedication()) {
PreparedStatement alternativeStatement = this.connection.prepareStatement(alternativeMedicationSQL);
alternativeStatement.setInt(1, newId);
alternativeStatement.setInt(2, alternative.getId());
alternativeStatement.execute();
}
} }
@Override @Override
public Medication read(int id) throws SQLException { public Medication read(int id) throws SQLException {
final String SQL = """ ResultSet result = getReadStatement(id).executeQuery();
SELECT medication.*, medication_ingredient.id
FROM medication
LEFT JOIN medication_ingredient ON medication.id = medication_ingredient.id
WHERE medication.id = ?
""";
PreparedStatement statement = this.connection.prepareStatement(SQL);
statement.setInt(1, id);
ResultSet result = statement.executeQuery();
return getInstanceFromResultSet(result); return getInstanceFromResultSet(result);
} }
@Override @Override
public List<Medication> readAll() throws SQLException { public List<Medication> readAll() throws SQLException {
final String SQL = """ final String SQL = """
SELECT medication.*, medication_ingredient.name SELECT medication.*, medication_ingredient.name, medication_alternative.alternativeId
FROM medication LEFT JOIN FROM medication
LEFT JOIN
medication_ingredient ON medication.id = medication_ingredient.id medication_ingredient ON medication.id = medication_ingredient.id
LEFT JOIN
medication_alternative ON medication.id = medication_alternative.id
"""; """;
ResultSet result = connection.prepareStatement(SQL).executeQuery(); ResultSet result = connection.prepareStatement(SQL).executeQuery();
List<Medication> medications = new ArrayList<>(); Map<Integer, Medication> medications = new HashMap<>();
Map<Integer, List<Ingredient>> ingredientMap = new HashMap<>(); Map<Integer, List<Ingredient>> ingredientMap = new HashMap<>();
Map<Integer, Set<Integer>> alternativesMap = new HashMap<>();
int currentMedicationId; int currentMedicationId;
int lastMedicationId = -1; int lastMedicationId = -1;
String latIngredient = "";
while (result.next()) { while (result.next()) {
currentMedicationId = result.getInt(1); currentMedicationId = result.getInt(1);
if (currentMedicationId != lastMedicationId) { if (currentMedicationId != lastMedicationId) {
@ -103,27 +109,42 @@ public class MedicationDao implements Dao<Medication> {
new ArrayList<>(), new ArrayList<>(),
result.getString(4), result.getString(4),
result.getString(5), result.getString(5),
result.getInt(6) result.getInt(6),
new ArrayList<>()
); );
medications.add(medication); medications.put(currentMedicationId, medication);
} }
List<Ingredient> ingredients = ingredientMap.computeIfAbsent(currentMedicationId, k -> new ArrayList<>()); List<Ingredient> ingredients = ingredientMap.computeIfAbsent(currentMedicationId, k -> new ArrayList<>());
String ingredientName = result.getString(7); String ingredientName = result.getString(7);
if(ingredientName == null){ if (ingredientName != null && !latIngredient.equals(ingredientName)) {
continue; ingredients.add(new Ingredient(ingredientName));
latIngredient = ingredientName;
} }
ingredients.add(new Ingredient(ingredientName));
Set<Integer> alternatives = alternativesMap.computeIfAbsent(currentMedicationId, k -> new HashSet<>());
int alternativeId = result.getInt(8);
if (alternativeId != 0) {
alternatives.add(alternativeId);
}
lastMedicationId = currentMedicationId; lastMedicationId = currentMedicationId;
} }
for (Medication medication : medications) { for (Medication medication : medications.values()) {
List<Ingredient> ingredients = ingredientMap.get(medication.getId()); List<Ingredient> ingredients = ingredientMap.get(medication.getId());
if(ingredients.isEmpty()){ if (ingredients.isEmpty()) {
continue; continue;
} }
medication.setIngredients(ingredientMap.get(medication.getId())); medication.setIngredients(ingredientMap.get(medication.getId()));
Set<Integer> alternativeIds = alternativesMap.get(medication.getId());
List<Medication> alternatives = new ArrayList<>();
for (Integer alternativeId : alternativeIds) {
alternatives.add(medications.get(alternativeId));
}
medication.setAlternativeMedication(alternatives);
} }
return medications; return medications.values().stream().toList();
} }
@Override @Override
@ -164,6 +185,25 @@ public class MedicationDao implements Dao<Medication> {
statement.setString(2, ingredient.getName()); statement.setString(2, ingredient.getName());
statement.execute(); statement.execute();
} }
final String alternativeDeleteSQL = """
DELETE FROM medication_alternative WHERE id = ?
""";
PreparedStatement alternativeStatement = this.connection.prepareStatement(alternativeDeleteSQL);
alternativeStatement.setInt(1, medication.getId());
alternativeStatement.executeUpdate();
final String alternativeCreateSQL = """
INSERT INTO medication_alternative
(id, alternativeId)
VALUES (?, ?);
""";
for (Medication alternative : medication.getAlternativeMedication()) {
PreparedStatement statement = this.connection.prepareStatement(alternativeCreateSQL);
statement.setInt(1, medication.getId());
statement.setInt(2, alternative.getId());
statement.execute();
}
} }
@Override @Override
@ -176,6 +216,23 @@ public class MedicationDao implements Dao<Medication> {
preparedStatement.executeUpdate(); preparedStatement.executeUpdate();
} }
/**
* @param id The ID of the database entry to read.
* @return A {@link PreparedStatement} to read a specific entry by its ID.
*/
public PreparedStatement getReadStatement(int id) throws SQLException {
final String SQL = """
SELECT medication.*, medication_ingredient.name, medication_alternative.alternativeId
FROM medication
LEFT JOIN medication_ingredient ON medication.id = medication_ingredient.id
LEFT JOIN medication_alternative ON medication.id = medication_alternative.id
WHERE medication.id = ?
""";
PreparedStatement statement = this.connection.prepareStatement(SQL);
statement.setInt(1, id);
return statement;
}
/** /**
* Constructs a {@link Medication} object from the {@link ResultSet} obtained after executing a database query. * Constructs a {@link Medication} object from the {@link ResultSet} obtained after executing a database query.
* This method is used internally to map the {@link ResultSet} data to a {@link Medication} object. * This method is used internally to map the {@link ResultSet} data to a {@link Medication} object.
@ -188,18 +245,40 @@ public class MedicationDao implements Dao<Medication> {
result.getInt(1), result.getInt(1),
result.getString(2), result.getString(2),
result.getString(3), result.getString(3),
List.of(), new ArrayList<>(),
result.getString(4), result.getString(4),
result.getString(5), result.getString(5),
result.getInt(6) result.getInt(6),
new ArrayList<>()
); );
List<Ingredient> ingredients = new ArrayList<>(); List<Ingredient> ingredients = new ArrayList<>();
List<Medication> alternatives = new ArrayList<>();
while (result.next()) { while (result.next()) {
ingredients.add(new Ingredient(result.getString(2))); String ingredientName = result.getString(7);
if (ingredientName != null) {
ingredients.add(new Ingredient(ingredientName));
}
int alternativeId = result.getInt(8);
if (alternativeId != 0) {
ResultSet alternativeResult = getReadStatement(alternativeId).executeQuery();
Medication alternativeMedication = new Medication(
alternativeResult.getInt(1),
alternativeResult.getString(2),
alternativeResult.getString(3),
new ArrayList<>(),
alternativeResult.getString(4),
alternativeResult.getString(5),
alternativeResult.getInt(6),
new ArrayList<>()
);
alternatives.add(alternativeMedication);
}
} }
medication.setIngredients(ingredients); medication.setIngredients(ingredients);
medication.setAlternativeMedication(alternatives);
return medication; return medication;
} }
} }

View file

@ -0,0 +1,7 @@
CREATE TABLE medication_alternative
(
id INTEGER NOT NULL ,
alternativeId INTEGER NOT NULL ,
FOREIGN KEY (id) REFERENCES medication (id) ON DELETE CASCADE,
FOREIGN KEY (alternativeId) REFERENCES medication (id) ON DELETE CASCADE
)